using DirectShowLib;
using Dowding.Model;
using GMap.NET;
using GMap.NET.WindowsForms;
using GMap.NET.WindowsForms.Markers;
using log4net;
using Microsoft.Scripting.Utils;
using MissionPlanner.ArduPilot;
using MissionPlanner.Controls;
using MissionPlanner.GeoRef;
using MissionPlanner.Joystick;
using MissionPlanner.Log;
using MissionPlanner.Maps;
using MissionPlanner.Utilities;
using MissionPlanner.Warnings;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using WebCamService;
using ZedGraph;
using LogAnalyzer = MissionPlanner.Utilities.LogAnalyzer;
using TableLayoutPanelCellPosition = System.Windows.Forms.TableLayoutPanelCellPosition;
using UnauthorizedAccessException = System.UnauthorizedAccessException;

// written by michael oborne

namespace MissionPlanner.GCSViews
{
    public partial class FlightData : MyUserControl, IActivate, IDeactivate
    {
        public static FlightData instance;
        public static GMapOverlay kmlpolygons;
        public static HUD myhud;
        public static readonly GStreamer hudGStreamer = new GStreamer();
        public static myGMAP mymap;
        public static bool threadrun;
        public SplitContainer MainHcopy;
        internal static GMapOverlay geofence;
        internal static GMapOverlay photosoverlay;
        internal static GMapOverlay poioverlay = new GMapOverlay("POI");
        internal static GMapOverlay cameraBounds;
        internal static GMapOverlay rallypointoverlay;
        internal static GMapOverlay tfrpolygons;
        internal GMapMarker CurrentGMapMarker;

        internal PointLatLng MouseDownStart;

        //The file path of the selected script
        internal string selectedscript = "";

        private static readonly ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
        AviWriter aviwriter;
        private bool CameraOverlap;
        GMapMarker center = new GMarkerGoogle(new PointLatLng(0.0, 0.0), GMarkerGoogleType.none);
        bool huddropout;
        bool huddropoutresize;

        /// <summary>
        /// Try to reduce the number of map position changes generated by the code
        /// </summary>
        DateTime lastmapposchange = DateTime.MinValue;

        DateTime lastscreenupdate = DateTime.UtcNow;
        RollingPointPairList list1 = new RollingPointPairList(1200);
        CurveItem list1curve;
        PropertyInfo list1item;
        RollingPointPairList list2 = new RollingPointPairList(1200);
        CurveItem list2curve;
        PropertyInfo list2item;
        RollingPointPairList list3 = new RollingPointPairList(1200);
        CurveItem list3curve;
        PropertyInfo list3item;
        RollingPointPairList list4 = new RollingPointPairList(1200);
        CurveItem list4curve;
        PropertyInfo list4item;
        RollingPointPairList list5 = new RollingPointPairList(1200);
        CurveItem list5curve;
        PropertyInfo list5item;
        RollingPointPairList list6 = new RollingPointPairList(1200);
        CurveItem list6curve;
        PropertyInfo list6item;
        RollingPointPairList list7 = new RollingPointPairList(1200);
        CurveItem list7curve;
        PropertyInfo list7item;
        RollingPointPairList list8 = new RollingPointPairList(1200);
        CurveItem list8curve;
        PropertyInfo list8item;
        RollingPointPairList list9 = new RollingPointPairList(1200);
        CurveItem list9curve;
        PropertyInfo list9item;
        RollingPointPairList list10 = new RollingPointPairList(1200);
        CurveItem list10curve;
        PropertyInfo list10item;
        RollingPointPairList list11 = new RollingPointPairList(1200);
        CurveItem list11curve;
        PropertyInfo list11item;
        RollingPointPairList list12 = new RollingPointPairList(1200);
        CurveItem list12curve;
        PropertyInfo list12item;
        RollingPointPairList list13 = new RollingPointPairList(1200);
        CurveItem list13curve;
        PropertyInfo list13item;
        RollingPointPairList list14 = new RollingPointPairList(1200);
        CurveItem list14curve;
        PropertyInfo list14item;
        RollingPointPairList list15 = new RollingPointPairList(1200);
        CurveItem list15curve;
        PropertyInfo list15item;
        RollingPointPairList list16 = new RollingPointPairList(1200);
        CurveItem list16curve;
        PropertyInfo list16item;
        RollingPointPairList list17 = new RollingPointPairList(1200);
        CurveItem list17curve;
        PropertyInfo list17item;
        RollingPointPairList list18 = new RollingPointPairList(1200);
        CurveItem list18curve;
        PropertyInfo list18item;
        RollingPointPairList list19 = new RollingPointPairList(1200);
        CurveItem list19curve;
        PropertyInfo list19item;
        RollingPointPairList list20 = new RollingPointPairList(1200);
        CurveItem list20curve;
        PropertyInfo list20item;
        double LogPlayBackSpeed = 1.0;
        GMapMarker marker;

        int messagecount;

        //whether or not the output console has already started
        bool outputwindowstarted;

        bool playingLog;
        GMapOverlay polygons;
        private Propagation prop;

        GMapRoute route;
        GMapOverlay routes;
        GMapOverlay adsbais;

        Script script;

        //whether or not a script is running
        bool scriptrunning;
        // A simple variable does not work on release builds...
        Semaphore scriptstarted = new Semaphore(1,1);

        //the thread the script is running on
        Thread scriptthread;

        public readonly List<TabPage> TabListOriginal = new List<TabPage>();
        public Dictionary<string,bool> TabListDisplay = new Dictionary<string, bool>();

        //List for setting colors of quick tab numbers
        List<Color> listQuickView = new List<Color>();
        //works well for dark background
        Color[] colorsForDefaultQuickView = new Color[] { Color.Blue, Color.Yellow, Color.Pink, Color.LimeGreen, Color.Orange, Color.Aqua, Color.LightCoral, Color.LightSteelBlue, Color.DarkKhaki, Color.LightYellow, Color.Violet, Color.YellowGreen, Color.OrangeRed, Color.Tomato, Color.Teal, Color.CornflowerBlue };

        Thread thisthread;

        int tickStart;
        //      private DockStateSerializer _serializer = null;

        List<PointLatLng> trackPoints = new List<PointLatLng>();
        volatile int updateBindingSourcecount;

        object updateBindingSourcelock = new object();

        string updateBindingSourceThreadName = "";

        public enum actions
        {
            Loiter_Unlim,
            Return_To_Launch,
            Preflight_Calibration,
            Mission_Start,
            Preflight_Reboot_Shutdown,
            Trigger_Camera,
            System_Time,
            Battery_Reset,
            ADSB_Out_Ident,
            Scripting_cmd_stop_and_restart,
            Scripting_cmd_stop,
            HighLatency_Enable,
            HighLatency_Disable,
            Toggle_Safety_Switch,
            Do_Parachute,
            Engine_Start,
            Engine_Stop,
            Terminate_Flight,
            Format_SD_Card,
        }

        private Dictionary<int, string> NIC_table = new Dictionary<int, string>()
        {
            {0, "UNKNOWN" },
            {1, "<20.0NM" },
            {2, "<8.0NM" },
            {3, "<4.0NM" },
            {4, "<2.0NM" },
            {5, "<1.0NM" },
            {6, "<0.3NM" },
            {7, "<0.2NM" },
            {8, "<0.1NM" },
            {9, "<75m" },
            {10, "<25m" },
            {11, "<7.5m" }
        };
        private Dictionary<int, string> NACp_table = new Dictionary<int, string>()
        {
            {0, "UNKNOWN" },
            {1, "<10.0NM" },
            {2, "<4.0NM" },
            {3, "<2.0NM" },
            {4, "<1.0NM" },
            {5, "<0.5NM" },
            {6, "<0.3NM" },
            {7, "<0.1NM" },
            {8, "<0.05NM" },
            {9, "<30m" },
            {10, "<10m" },
            {11, "<3m" }
        };

        private bool transponderNeverConnected = true;

        public FlightData()
        {
            log.Info("Ctor Start");

            InitializeComponent();

            log.Info("Components Done");

            instance = this;

            this.SubMainLeft.Panel1.ControlAdded += (sender, e) => ManageLeftPanelVisibility();
            this.SubMainLeft.Panel1.ControlRemoved += (sender, e) => ManageLeftPanelVisibility();
            this.tabControlactions.ControlAdded += (sender, e) => ManageLeftPanelVisibility();
            this.tabControlactions.ControlRemoved += (sender, e) => ManageLeftPanelVisibility();
            this.panel_persistent.ControlAdded += (sender, e) => ManageLeftPanelVisibility();
            this.panel_persistent.ControlRemoved += (sender, e) => ManageLeftPanelVisibility();
            //    _serializer = new DockStateSerializer(dockContainer1);
            //    _serializer.SavePath = Application.StartupPath + Path.DirectorySeparatorChar + "FDscreen.xml";
            //    dockContainer1.PreviewRenderer = new PreviewRenderer();
            //
            mymap = gMapControl1;
            myhud = hud1;
            MainHcopy = MainH;

            mymap.Paint += mymap_Paint;

            // populate the unmodified base list
            tabControlactions.TabPages.ForEach(i => { TabListOriginal.Add((TabPage) i); });

            //  mymap.Manager.UseMemoryCache = false;

            log.Info("Tunning Graph Settings");
            // setup default tuning graph
            if (Settings.Instance["Tuning_Graph_Selected"] != null)
            {
                string line = Settings.Instance["Tuning_Graph_Selected"].ToString();
                string[] lines = line.Split(new[] {'|'}, StringSplitOptions.RemoveEmptyEntries);
                foreach (string option in lines)
                {
                    string name = option;
                    if (option.StartsWith("customfield"))
                    {
                        // add empty custom felids so the are un-tickable
                        if (option.Length <= 12)
                        {
                            // string only contains key
                            CurrentState.custom_field_names.Add(option, "Unknown");
                        }
                        else
                        {
                            // both key and name
                            name = option.Substring(0,12);
                            CurrentState.custom_field_names.Add(name, option.Substring(12));
                        }
                    }
                    string desc = MainV2.comPort.MAV.cs.GetNameandUnit(name);
                    using (var cb = new CheckBox {Name = name, Checked = true, Text = desc})
                    {
                        chk_box_tunningCheckedChanged(cb, EventArgs.Empty);
                    }
                }
            }
            else
            {
                using (var cb = new CheckBox {Name = "roll", Checked = true})
                {
                    chk_box_tunningCheckedChanged(cb, EventArgs.Empty);
                }

                using (var cb = new CheckBox {Name = "pitch", Checked = true})
                {
                    chk_box_tunningCheckedChanged(cb, EventArgs.Empty);
                }

                using (var cb = new CheckBox {Name = "nav_roll", Checked = true})
                {
                    chk_box_tunningCheckedChanged(cb, EventArgs.Empty);
                }

                using (var cb = new CheckBox {Name = "nav_pitch", Checked = true})
                {
                    chk_box_tunningCheckedChanged(cb, EventArgs.Empty);
                }
            }

            /* It comes from the Theme not from the settings
            if (!string.IsNullOrEmpty(Settings.Instance["hudcolor"]))
            {
                hud1.hudcolor = Color.FromName(Settings.Instance["hudcolor"]);
            }
            */

            log.Info("HUD Settings");
            foreach (string item in Settings.Instance.Keys)
            {
                if (item.StartsWith("hud1_useritem_"))
                {
                    string selection = item.Replace("hud1_useritem_", "");

                    HUD.Custom cust = new HUD.Custom();
                    cust.Header = Settings.Instance[item];
                    HUD.Custom.src = MainV2.comPort.MAV.cs;

                    addHudUserItem(ref cust, selection);

                }
            }

            CMB_action.DataSource = Enum.GetNames(typeof(actions));

            CMB_modes.DataSource = ArduPilot.Common.getModesList(MainV2.comPort.MAV.cs.firmware);
            CMB_modes.ValueMember = "Key";
            CMB_modes.DisplayMember = "Value";

            //default to auto
            CMB_modes.Text = "Auto";

            CMB_setwp.SelectedIndex = 0;

            log.Info("Graph Setup");
            CreateChart(zg1);

            // config map
            log.Info("Map Setup");
            gMapControl1.CacheLocation = Settings.GetDataDirectory() +
                                         "gmapcache" + Path.DirectorySeparatorChar;
            gMapControl1.MinZoom = 0;
            gMapControl1.MaxZoom = 24;
            gMapControl1.Zoom = 3;

            gMapControl1.OnMapZoomChanged += gMapControl1_OnMapZoomChanged;

            gMapControl1.DisableFocusOnMouseEnter = true;

            gMapControl1.OnMarkerEnter += gMapControl1_OnMarkerEnter;
            gMapControl1.OnMarkerLeave += gMapControl1_OnMarkerLeave;

            gMapControl1.RoutesEnabled = true;
            gMapControl1.PolygonsEnabled = true;

            tfrpolygons = new GMapOverlay("tfrpolygons");
            gMapControl1.Overlays.Add(tfrpolygons);

            kmlpolygons = new GMapOverlay("kmlpolygons");
            gMapControl1.Overlays.Add(kmlpolygons);

            geofence = new GMapOverlay("geofence");
            gMapControl1.Overlays.Add(geofence);

            polygons = new GMapOverlay("polygons");
            gMapControl1.Overlays.Add(polygons);

            photosoverlay = new GMapOverlay("photos overlay");
            gMapControl1.Overlays.Add(photosoverlay);

            cameraBounds = new GMapOverlay("camera bounds");
            gMapControl1.Overlays.Add(cameraBounds);

            routes = new GMapOverlay("routes");
            gMapControl1.Overlays.Add(routes);

            adsbais = new GMapOverlay("adsb/ais");
            gMapControl1.Overlays.Add(adsbais);

            rallypointoverlay = new GMapOverlay("rally points");
            gMapControl1.Overlays.Add(rallypointoverlay);

            gMapControl1.Overlays.Add(poioverlay);

            float gspeedMax = Settings.Instance.GetFloat("GspeedMAX");
            if (gspeedMax != 0)
            {
                Gspeed.MaxValue = gspeedMax;
            }

            MainV2.comPort.ParamListChanged += FlightData_ParentChanged;

            //HUD Theming, color setup
            myhud.groundColor1 = ThemeManager.HudGroundTop;
            myhud.groundColor2 = ThemeManager.HudGroundBot;
            myhud.skyColor1 = ThemeManager.HudSkyTop;
            myhud.skyColor2 = ThemeManager.HudSkyBot;
            myhud.hudcolor = ThemeManager.HudText;

            hud1.displayicons = Settings.Instance.GetBoolean("HUD_showicons", false);

            tabControlactions.Multiline = Settings.Instance.GetBoolean("tabControlactions_Multiline", false);

        }

        public void Activate()
        {
            log.Info("Activate Called");

            OnResize(EventArgs.Empty);

            if (CB_tuning.Checked)
                ZedGraphTimer.Start();

            hud1.altunit = CurrentState.AltUnit;
            hud1.speedunit = CurrentState.SpeedUnit;
            hud1.distunit = CurrentState.DistanceUnit;
            coords1.AltUnit = CurrentState.AltUnit;

            if (MainV2.MONO)
            {
                if (!hud1.Visible)
                    hud1.Visible = true;
                if (!hud1.Enabled)
                    hud1.Enabled = true;

                hud1.Dock = DockStyle.Fill;
            }

            if (Settings.Instance.ContainsKey("quickViewRows"))
            {
                setQuickViewRowsCols(Settings.Instance["quickViewCols"], Settings.Instance["quickViewRows"]);
            }

            for (int f = 1; f < 30; f++)
            {
                // load settings
                if (Settings.Instance["quickView" + f] != null)
                {
                    Control[] ctls = Controls.Find("quickView" + f, true);
                    if (ctls.Length > 0)
                    {
                        QuickView QV = (QuickView) ctls[0];

                        // set description and unit
                        string desc = Settings.Instance["quickView" + f];
                        if (QV.Tag == null)
                            QV.Tag = desc;
                        QV.desc = MainV2.comPort.MAV.cs.GetNameandUnit(desc);

                        // set databinding for value
                        QV.DataBindings.Clear();
                        try
                        {
                            var b = new Binding("number", bindingSourceQuickTab,
                                Settings.Instance["quickView" + f], true);
                            b.Format += new ConvertEventHandler(BindingTypeToNumber);
                            b.Parse += new ConvertEventHandler(NumberToBindingType);

                            QV.DataBindings.Add(b);
                        }
                        catch (Exception ex)
                        {
                            log.Debug(ex);
                        }
                    }
                }
                else
                {
                    // if no config, update description on predefined
                    try
                    {
                        Control[] ctls = Controls.Find("quickView" + f, true);
                        if (ctls.Length > 0)
                        {
                            QuickView QV = (QuickView) ctls[0];
                            string desc = QV.desc;
                            if (QV.Tag == null)
                                QV.Tag = desc;
                            QV.desc = MainV2.comPort.MAV.cs.GetNameandUnit(QV.Tag.ToString());
                        }
                    }
                    catch (Exception ex)
                    {
                        log.Debug(ex);
                    }
                }
            }

            CheckBatteryShow();

            // make sure the hud user items/warnings/checklist are using the current state
            HUD.Custom.src = MainV2.comPort.MAV.cs;
            CustomWarning.defaultsrc = MainV2.comPort.MAV.cs;
            MissionPlanner.Controls.PreFlight.CheckListItem.defaultsrc = MainV2.comPort.MAV.cs;

            if (Settings.Instance["maplast_lat"] != "")
            {
                try
                {
                    gMapControl1.Position = new PointLatLng(Settings.Instance.GetDouble("maplast_lat"),
                        Settings.Instance.GetDouble("maplast_lng"));
                    if (Math.Round(Settings.Instance.GetDouble("maplast_lat"), 1) == 0)
                    {
                        // no zoom in
                        Zoomlevel.Value = 3;
                        TRK_zoom.Value = 3;
                    }
                    else
                    {
                        var zoom = Settings.Instance.GetFloat("maplast_zoom");
                        if (Zoomlevel.Maximum < (decimal) zoom)
                            zoom = (float) Zoomlevel.Maximum;
                        Zoomlevel.Value = (decimal) zoom;
                        TRK_zoom.Value = (float) Zoomlevel.Value;
                    }
                }
                catch
                {
                }
            }

            // update tabs displayed
            updateDisplayView();

            hud1.doResize();
        }

        public void BUT_playlog_Click(object sender, EventArgs e)
        {
            if (MainV2.comPort.logreadmode)
            {
                MainV2.comPort.logreadmode = false;
                ZedGraphTimer.Stop();
                playingLog = false;
            }
            else
            {
                // BUT_clear_track_Click(sender, e);
                MainV2.comPort.logreadmode = true;
                list1.Clear();
                list2.Clear();
                list3.Clear();
                list4.Clear();
                list5.Clear();
                list6.Clear();
                list7.Clear();
                list8.Clear();
                list9.Clear();
                list10.Clear();
                list11.Clear();
                list12.Clear();
                list13.Clear();
                list14.Clear();
                list15.Clear();
                list16.Clear();
                list17.Clear();
                list18.Clear();
                list19.Clear();
                list20.Clear();
                tickStart = Environment.TickCount;

                zg1.GraphPane.XAxis.Scale.Min = 0;
                zg1.GraphPane.XAxis.Scale.Max = 1;
                ZedGraphTimer.Start();
                playingLog = true;
            }
        }

        public void CheckBatteryShow()
        {
            //Check if we want to display calculated battery cell voltage
            hud1.displayCellVoltage = Settings.Instance.GetBoolean("HUD_showbatterycell", false);
            hud1.batterycellcount = Settings.Instance.GetInt32("HUD_batterycellcount", 0);
        }

        public void CreateChart(ZedGraphControl zgc)
        {
            if (zgc == null) throw new ArgumentNullException(nameof(zgc));

            GraphPane myPane = zgc.GraphPane;

            // Set the titles and axis labels
            myPane.Title.Text = "Tuning - Double click to change items";
            myPane.XAxis.Title.Text = "Time (s)";
            myPane.YAxis.Title.Text = "Unit";
            myPane.YAxis.Title.FontSpec.Size += 2;

            // Show the x axis grid
            myPane.XAxis.MajorGrid.IsVisible = true;

            myPane.XAxis.Scale.Min = 0;
            myPane.XAxis.Scale.Max = 5;

            // Make the Y axis scale red
            myPane.YAxis.Scale.FontSpec.FontColor = Color.White;
            myPane.YAxis.Title.FontSpec.FontColor = Color.White;
            // turn off the opposite tics so the Y tics don't show up on the Y2 axis
            myPane.YAxis.MajorTic.IsOpposite = false;
            myPane.YAxis.MinorTic.IsOpposite = false;
            // Don't display the Y zero line
            myPane.YAxis.MajorGrid.IsZeroLine = true;
            // Align the Y axis labels so they are flush to the axis
            myPane.YAxis.Scale.Align = AlignP.Inside;
            // Manually set the axis range
            //myPane.YAxis.Scale.Min = -1;
            //myPane.YAxis.Scale.Max = 1;

            // Fill the axis background with a gradient
            //myPane.Chart.Fill = new Fill(Color.White, Color.LightGray, 45.0f);

            // Sample at 50ms intervals
            ZedGraphTimer.Interval = 200;
            //timer1.Enabled = true;
            //timer1.Start();


            // Calculate the Axis Scale Ranges
            //zgc.AxisChange();

            tickStart = Environment.TickCount;
        }

        public void Deactivate()
        {
            if (MainV2.MONO)
            {
                hud1.Dock = DockStyle.None;
                hud1.Size = new Size(5, 5);
                hud1.Enabled = false;
                hud1.Visible = false;
            }
            //     hud1.Location = new Point(-1000,-1000);

            Settings.Instance["maplast_lat"] = gMapControl1.Position.Lat.ToString();
            Settings.Instance["maplast_lng"] = gMapControl1.Position.Lng.ToString();
            Settings.Instance["maplast_zoom"] = gMapControl1.Zoom.ToString();

            ZedGraphTimer.Stop();
        }

        public void LoadLogFile(string file)
        {
            if (file != "")
            {
                try
                {
                    tlogdir = Path.GetDirectoryName(file);

                    BUT_clear_track_Click(null, null);

                    MainV2.comPort.logreadmode = true;
                    MainV2.comPort.logplaybackfile = new BinaryReader(File.OpenRead(file));
                    MainV2.comPort.lastlogread = DateTime.MinValue;

                    LBL_logfn.Text = Path.GetFileName(file);

                    log.Info("Open logfile " + file);

                    MainV2.comPort.getHeartBeat();

                    tracklog.Value = 0;
                    tracklog.Minimum = 0;
                    tracklog.Maximum = 100;
                }
                catch
                {
                    CustomMessageBox.Show(Strings.PleaseLoadValidFile, Strings.ERROR);
                }
            }
        }

        private void updateDisplayTabControlActions()
        {
            TabListDisplay.Clear();

            TabListDisplay.Add(tabQuick.Name, MainV2.DisplayConfiguration.displayQuickTab);

            TabListDisplay.Add(tabPagePreFlight.Name, MainV2.DisplayConfiguration.displayPreFlightTab);

            TabListDisplay.Add(tabActions.Name, MainV2.DisplayConfiguration.displayAdvActionsTab);

            TabListDisplay.Add(tabActionsSimple.Name, MainV2.DisplayConfiguration.displaySimpleActionsTab);

            TabListDisplay.Add(tabGauges.Name, MainV2.DisplayConfiguration.displayGaugesTab);

            TabListDisplay.Add(tabStatus.Name, MainV2.DisplayConfiguration.displayStatusTab);

            TabListDisplay.Add(tabServo.Name, MainV2.DisplayConfiguration.displayServoTab);

            TabListDisplay.Add(tabScripts.Name, MainV2.DisplayConfiguration.displayScriptsTab);

            TabListDisplay.Add(tabTLogs.Name, MainV2.DisplayConfiguration.displayTelemetryTab);

            TabListDisplay.Add(tablogbrowse.Name, MainV2.DisplayConfiguration.displayDataflashTab);

            TabListDisplay.Add(tabPagemessages.Name, MainV2.DisplayConfiguration.displayMessagesTab);

            TabListDisplay.Add(tabTransponder.Name, MainV2.DisplayConfiguration.displayTransponderTab);

            TabListDisplay.Add(tabAuxFunction.Name, MainV2.DisplayConfiguration.displayAuxFunctionTab);

            TabListDisplay.Add(tabPayload.Name, MainV2.DisplayConfiguration.displayPayloadTab);
        }

        private void loadTabControlActions()
        {
            string tabs = Settings.Instance["tabcontrolactions"];

            if (String.IsNullOrEmpty(tabs) || TabListOriginal == null || TabListOriginal.Count == 0)
                return;

            string[] tabarray = tabs.Split(';');

            if (tabarray.Length == 0)
                return;

            tabControlactions.TabPages.Clear();

            foreach (var tabname in tabarray)
            {
                bool added = false;
                foreach (TabPage tabPage in TabListOriginal)
                {
                    if (tabPage.Name == tabname && ((TabListDisplay.ContainsKey(tabname) && TabListDisplay[tabname] == true) || !TabListDisplay.ContainsKey(tabname)))
                    {
                        tabControlactions.TabPages.Add(tabPage);
                        log.Debug("add tabControlactions " + tabPage.Name);
                        added = true;
                        break;
                    }
                }

                if(!added)
                    log.Debug("not added to tabControlactions " + tabname);
            }
        }

        public void updateDisplayView()
        {
            updateDisplayTabControlActions();

            loadTabControlActions();

            //we want to at least have one tabpage
            if (tabControlactions.TabPages.Count == 0)
            {
                tabControlactions.TabPages.Add(tabQuick);
                tabControlactions.SelectedIndex = 0;
            }

            ThemeManager.ApplyThemeTo(tabControlactions);
        }

        internal void BUT_run_script_Click(object sender, EventArgs e)
        {
            if (File.Exists(selectedscript))
            {
                scriptthread = new Thread(run_selected_script)
                {
                    IsBackground = true,
                    Name = "Script Thread (new)"
                };
                labelScriptStatus.Text = "Script Status: Running";

                script = null;
                outputwindowstarted = false;
                scriptstarted.WaitOne();

                scriptthread.Start();
                scriptrunning = true;
                BUT_run_script.Enabled = false;
                BUT_select_script.Enabled = false;
                BUT_abort_script.Visible = true;
                BUT_edit_selected.Enabled = false;
                scriptChecker.Enabled = true;
                checkBoxRedirectOutput.Enabled = false;

                scriptstarted.WaitOne();
                scriptstarted.Release();

                scriptChecker_Tick(null, null);

                MissionPlanner.Utilities.Tracking.AddPage(
                    System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.ToString(),
                    System.Reflection.MethodBase.GetCurrentMethod().Name);
            }
            else
            {
                CustomMessageBox.Show("Please select a valid script", "Bad Script");
            }
        }

        protected override void Dispose(bool disposing)
        {
            base.Dispose(disposing);

            MainV2.comPort.logreadmode = false;
            try
            {
                if (hud1 != null)
                    Settings.Instance["FlightSplitter"] = MainH.SplitterDistance.ToString();
            }
            catch
            {
            }

            if (polygons != null)
                polygons.Dispose();
            if (routes != null)
                routes.Dispose();
            if (route != null)
                route.Dispose();
            if (marker != null)
                marker.Dispose();
            if (aviwriter != null)
                aviwriter.Dispose();

            if (prop != null)
                prop.Stop();

            if (disposing && (components != null))
            {
                components.Dispose();
            }
        }

        protected override void OnInvalidated(InvalidateEventArgs e)
        {
            base.OnInvalidated(e);
            updateBindingSourceWork();
        }

        protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
        {
            if (keyData == (Keys.Control | Keys.D1))
            {
                tabControlactions.SelectedIndex = 0;
                return true;
            }
            else if (keyData == (Keys.Control | Keys.D2))
            {
                tabControlactions.SelectedIndex = 1;
                return true;
            }
            else if (keyData == (Keys.Control | Keys.D3))
            {
                tabControlactions.SelectedIndex = 2;
                return true;
            }
            else if (keyData == (Keys.Control | Keys.D4))
            {
                tabControlactions.SelectedIndex = 3;
                return true;
            }
            else if (keyData == (Keys.Control | Keys.D5))
            {
                tabControlactions.SelectedIndex = 4;
                return true;
            }
            else if (keyData == (Keys.Control | Keys.D6))
            {
                tabControlactions.SelectedIndex = 5;
                return true;
            }
            else if (keyData == (Keys.Control | Keys.D7))
            {
                tabControlactions.SelectedIndex = 6;
                return true;
            }
            else if (keyData == (Keys.Control | Keys.D8))
            {
                tabControlactions.SelectedIndex = 7;
                return true;
            }
            else if (keyData == (Keys.Control | Keys.D9))
            {
                tabControlactions.SelectedIndex = 8;
                return true;
            }
            else if (keyData == (Keys.Control | Keys.D0))
            {
                tabControlactions.SelectedIndex = 9;
                return true;
            }

            if (keyData == (Keys.Space))
            {
                if (MainV2.comPort.logplaybackfile != null)
                {
                    BUT_playlog_Click(null, null);
                    return true;
                }
            }
            else if (keyData == (Keys.Subtract))
            {
                if (LogPlayBackSpeed > 1)
                    LogPlayBackSpeed--;
                else
                    LogPlayBackSpeed /= 2;

                updateLogPlayPosition();
            }
            else if (keyData == (Keys.Add))
            {
                if (LogPlayBackSpeed > 1)
                    LogPlayBackSpeed++;
                else
                    LogPlayBackSpeed *= 2;

                updateLogPlayPosition();
            }

            return false;
        }

        void addHudUserItem(ref HUD.Custom cust, string name)
        {
            setupPropertyInfo(ref cust.Item, name, MainV2.comPort.MAV.cs);

            hud1.CustomItems[name] = cust;

            hud1.Invalidate();
        }

        private void addMissionPhotoMarker(GMapMarker marker)
        {
            BeginInvoke((Action) delegate { photosoverlay.Markers.Add(marker); });
        }

        private void addMAVMarker(MAVState MAV)
        {
            this.BeginInvokeIfRequired(() =>
            {
                var marker = Common.getMAVMarker(MAV, routes);

                if (marker == null || marker.Position.Lat == 0 && marker.Position.Lng == 0)
                    return;

                addMissionRouteMarker(marker);
            });
        }

        private void addMissionRouteMarker(GMapMarker marker)
        {
            if (marker == null) return;

            this.BeginInvokeIfRequired((Action) delegate
            {
                routes.Markers.InsertSorted(marker, Comparer<GMapMarker>.Create((a, b) =>
                {
                    var bvalue = 0;
                    if (b is GMapMarkerBoat)
                        bvalue = 0;
                    else if (b is GMapMarkerRover)
                        bvalue = 1;
                    else if (b is GMapMarkerPlane)
                        bvalue = 2;
                    else if (b is GMapMarkerQuad)
                        bvalue = 3;

                    if (a is GMapMarkerBoat)
                        return 0.CompareTo(bvalue);
                    else if (a is GMapMarkerRover)
                        return 1.CompareTo(bvalue);
                    else if (a is GMapMarkerPlane)
                        return 2.CompareTo(bvalue);
                    else if (a is GMapMarkerQuad)
                        return 3.CompareTo(bvalue);

                    return a.GetType().Name.CompareTo(b.GetType().Name);
                }));
            });
        }

        private void addPoiToolStripMenuItem_Click(object sender, EventArgs e)
        {
            POI.POIAdd(MouseDownStart);
        }

        private void BUT_abort_script_Click(object sender, EventArgs e)
        {
            scriptthread.Abort();
            scriptrunning = false;
            BUT_abort_script.Visible = false;
        }

        private void BUT_abortland_Click(object sender, EventArgs e)
        {
            if (!MainV2.comPort.BaseStream.IsOpen)
                return;

            try
            {
                MainV2.comPort.doAbortLand();
            }
            catch
            {
                CustomMessageBox.Show(Strings.CommandFailed, Strings.ERROR);
            }
        }

        private void BUT_ARM_Click(object sender, EventArgs e)
        {
            if (!MainV2.comPort.BaseStream.IsOpen)
                return;

            // arm the MAV
            try
            {
                var isitarmed = MainV2.comPort.MAV.cs.armed;
                var action = MainV2.comPort.MAV.cs.armed ? "Disarm" : "Arm";

                if (isitarmed)
                    if (CustomMessageBox.Show("Are you sure you want to " + action, action,
                            CustomMessageBox.MessageBoxButtons.YesNo) !=
                        CustomMessageBox.DialogResult.Yes)
                        return;
                StringBuilder sb = new StringBuilder();
                var sub = MainV2.comPort.SubscribeToPacketType(MAVLink.MAVLINK_MSG_ID.STATUSTEXT, message =>
                {
                    sb.AppendLine(Encoding.ASCII.GetString(((MAVLink.mavlink_statustext_t) message.data).text)
                        .TrimEnd('\0'));
                    return true;
                }, (byte)MainV2.comPort.sysidcurrent, (byte)MainV2.comPort.compidcurrent);
                bool ans = MainV2.comPort.doARM(!isitarmed);
                MainV2.comPort.UnSubscribeToPacketType(sub);
                if (ans == false)
                {
                    if (CustomMessageBox.Show(
                            action + " failed.\n" + sb.ToString() + "\nForce " + action +
                            " can bypass safety checks,\nwhich can lead to the vehicle crashing\nand causing serious injuries.\n\nDo you wish to Force " +
                            action + "?", Strings.ERROR, CustomMessageBox.MessageBoxButtons.YesNo,
                            CustomMessageBox.MessageBoxIcon.Exclamation, "Force " + action, "Cancel") ==
                        CustomMessageBox.DialogResult.Yes)
                    {
                        ans = MainV2.comPort.doARM(!isitarmed, true);
                        if (ans == false)
                        {
                            CustomMessageBox.Show(Strings.ErrorRejectedByMAV, Strings.ERROR);
                        }
                    }
                }
            }
            catch
            {
                CustomMessageBox.Show(Strings.ErrorNoResponse, Strings.ERROR);
            }
        }

        private void but_bintolog_Click(object sender, EventArgs e)
        {
            using (OpenFileDialog ofd = new OpenFileDialog())
            {
                ofd.Filter = "Binary Log|*.bin;*.BIN";
                ofd.Multiselect = true;

                ofd.ShowDialog();

                foreach (string logfile in ofd.FileNames)
                {
                    string outfilename = Path.GetDirectoryName(logfile) + Path.DirectorySeparatorChar +
                                         Path.GetFileNameWithoutExtension(logfile) + ".log";

                    BinaryLog.ConvertBin(logfile, outfilename);
                }
            }
        }

        private void BUT_clear_track_Click(object sender, EventArgs e)
        {
            if (route != null)
                route.Points.Clear();

            if (MainV2.comPort.MAV.camerapoints != null)
                MainV2.comPort.MAV.camerapoints.Clear();
        }

        void but_Click(object sender, EventArgs e)
        {
            foreach (MainSwitcher.Screen sc in MainV2.View.screens)
            {
                if (sc.Name == "FlightPlanner")
                {
                    splitContainer1.Panel2.Controls.Remove(sc.Control);
                    splitContainer1.Panel2.Controls.Remove((Control) sender);
                    sc.Control.Visible = false;

                    if (sc.Control is IDeactivate)
                    {
                        ((IDeactivate) (sc.Control)).Deactivate();
                    }

                    break;
                }
            }

            foreach (Control ctl in splitContainer1.Panel2.Controls)
            {
                ctl.Visible = true;
            }
        }

        private void but_dflogtokml_Click(object sender, EventArgs e)
        {
            using (OpenFileDialog openFileDialog1 = new OpenFileDialog())
            {
                openFileDialog1.Filter = "Log Files|*.log;*.bin;*.BIN;*.LOG";
                openFileDialog1.FilterIndex = 2;
                openFileDialog1.RestoreDirectory = true;
                openFileDialog1.Multiselect = true;
                try
                {
                    openFileDialog1.InitialDirectory = tlogdir;
                }
                catch
                {
                } // incase dir doesnt exist

                if (openFileDialog1.ShowDialog() == DialogResult.OK)
                {
                    foreach (string logfile in openFileDialog1.FileNames)
                    {
                        LogOutput lo = new LogOutput();
                        try
                        {
                            StreamReader tr;

                            if (logfile.ToLower().EndsWith(".bin"))
                            {
                                using (tr = new StreamReader(logfile))
                                {
                                    GC.Collect();
                                    DFLogBuffer temp = new DFLogBuffer(tr.BaseStream);

                                    uint a = 0;
                                    foreach (var line in temp)
                                    {
                                        lo.processLine(line);
                                        a++;

                                        if ((a % 100000) == 0)
                                            Console.WriteLine(a);
                                    }

                                    temp.Dispose();
                                }
                            }
                            else
                            {
                                using (tr = new StreamReader(logfile))
                                {
                                    while (!tr.EndOfStream)
                                    {
                                        lo.processLine(tr.ReadLine());
                                    }

                                    tr.Close();
                                }
                            }
                        }
                        catch (Exception ex)
                        {
                            CustomMessageBox.Show("Error processing file. Make sure the file is not in use.\n" + ex);
                        }

                        lo.writeKML(logfile + ".kml");
                    }
                }
            }
        }

        private void BUT_DFMavlink_Click(object sender, EventArgs e)
        {
            var form = new LogDownloadMavLink();

            form.Show();
        }

        private void but_disablejoystick_Click(object sender, EventArgs e)
        {
            if (MainV2.joystick != null && MainV2.joystick.enabled)
            {
                MainV2.joystick.enabled = false;

                MainV2.joystick.clearRCOverride();

                but_disablejoystick.Visible = false;
            }
        }

        private void BUT_edit_selected_Click(object sender, EventArgs e)
        {
            try
            {
                ProcessStartInfo psi = new ProcessStartInfo(selectedscript);
                psi.UseShellExecute = true;
                Process.Start(psi);
            }
            catch
            {
            }
        }

        private void BUT_Homealt_Click(object sender, EventArgs e)
        {
            if (MainV2.comPort.MAV.cs.altoffsethome != 0)
            {
                MainV2.comPort.MAV.cs.altoffsethome = 0;
            }
            else
            {
                MainV2.comPort.MAV.cs.altoffsethome =
                    (float) (-MainV2.comPort.MAV.cs.HomeAlt / CurrentState.multiplieralt);
            }
        }

        private void BUT_joystick_Click(object sender, EventArgs e)
        {
            new JoystickSetup().ShowUserControl();
        }


        private void BUT_SendMSG_Click(object sender, EventArgs e)
        {
            if (!MainV2.comPort.BaseStream.IsOpen)
                return;

            // Send a message
            try
            {
                string txt = "";
                if (DialogResult.Cancel == InputBox.Show("Enter Message", "Enter Message to be logged", ref txt))
                    return;
                MainV2.comPort.send_text(5, txt);
            }
            catch
            {
                CustomMessageBox.Show(Strings.ErrorNoResponse, Strings.ERROR);
            }
        }

        private string tlogdir = Settings.Instance.LogDir;

        private void BUT_loadtelem_Click(object sender, EventArgs e)
        {
            LBL_logfn.Text = "";

            if (MainV2.comPort.logplaybackfile != null)
            {
                try
                {
                    MainV2.comPort.logplaybackfile.Close();
                    MainV2.comPort.logplaybackfile = null;
                }
                catch
                {
                }
            }

            using (OpenFileDialog fd = new OpenFileDialog())
            {
                fd.AddExtension = true;
                fd.Filter = "Telemetry log (*.tlog)|*.tlog;*.tlog.*|Mavlink Log (*.mavlog)|*.mavlog";
                fd.InitialDirectory = tlogdir;
                fd.DefaultExt = ".tlog";
                DialogResult result = fd.ShowDialog();
                string file = fd.FileName;
                LoadLogFile(file);
            }
        }

        private void BUT_log2kml_Click(object sender, EventArgs e)
        {
            Form frm = new MavlinkLog();
            ThemeManager.ApplyThemeTo(frm);
            frm.Show();
        }

        private void BUT_loganalysis_Click(object sender, EventArgs e)
        {
            using (OpenFileDialog ofd = new OpenFileDialog())
            {
                ofd.Filter = "*.log;*.bin|*.log;*.bin;*.BIN;*.LOG";
                ofd.InitialDirectory = tlogdir;
                ofd.ShowDialog();

                if (ofd.FileName != "")
                {
                    string newlogfile = null;

                    if (ofd.FileName.ToLower().EndsWith(".bin"))
                    {
                        newlogfile = Path.GetTempFileName() + ".log";

                        try
                        {
                            BinaryLog.ConvertBin(ofd.FileName, newlogfile);
                        }
                        catch (IOException ex)
                        {
                            CustomMessageBox.Show("File access issue: " + ex.Message, Strings.ERROR);
                            return;
                        }

                        ofd.FileName = newlogfile;
                    }

                    string xmlfile = LogAnalyzer.CheckLogFile(ofd.FileName);

                    GC.Collect();

                    if (File.Exists(xmlfile))
                    {
                        try
                        {
                            var out1 = LogAnalyzer.Results(xmlfile);

                            Controls.LogAnalyzer frm = new Controls.LogAnalyzer(out1);

                            ThemeManager.ApplyThemeTo(frm);

                            frm.Show();
                        }
                        catch (Exception ex)
                        {
                            CustomMessageBox.Show("Failed to load analyzer results\n" + ex.ToString());
                        }
                    }
                    else
                    {
                        CustomMessageBox.Show("Bad input file");
                    }

                    if (!String.IsNullOrEmpty(newlogfile))
                    {
                        try
                        {
                            File.Delete(newlogfile);
                        }
                        catch
                        {
                        }
                    }
                }
            }
        }

        private void BUT_logbrowse_Click(object sender, EventArgs e)
        {
            Form logbrowse = new LogBrowse();
            ThemeManager.ApplyThemeTo(logbrowse);
            logbrowse.Show();
        }

        private void BUT_matlab_Click(object sender, EventArgs e)
        {
            MatLabForms.ProcessLog();
        }

        private void BUT_mountmode_Click(object sender, EventArgs e)
        {
            try
            {
                if (MainV2.comPort.MAV.param.ContainsKey("MNT_MODE"))
                {
                    MainV2.comPort.setParam((byte) MainV2.comPort.sysidcurrent, (byte) MainV2.comPort.compidcurrent,
                        "MNT_MODE", (int) CMB_mountmode.SelectedValue);
                }
                else
                {
                    // copter 3.3 acks with an error, but is ok
                    MainV2.comPort.doCommand((byte) MainV2.comPort.sysidcurrent, (byte) MainV2.comPort.compidcurrent,
                        MAVLink.MAV_CMD.DO_MOUNT_CONTROL, 0, 0, 0, 0, 0, 0,
                        (int) CMB_mountmode.SelectedValue);
                }
            }
            catch
            {
                CustomMessageBox.Show(Strings.ErrorNoResponse, Strings.ERROR);
            }
        }

        private void BUT_quickauto_Click(object sender, EventArgs e)
        {
            try
            {
                ((Control) sender).Enabled = false;
                MainV2.comPort.setMode("Auto");
            }
            catch
            {
                CustomMessageBox.Show(Strings.CommandFailed, Strings.ERROR);
            }

            ((Control) sender).Enabled = true;
        }

        private void BUT_quickmanual_Click(object sender, EventArgs e)
        {
            try
            {
                ((Control) sender).Enabled = false;
                if (MainV2.comPort.MAV.cs.firmware == Firmwares.ArduPlane ||
                    MainV2.comPort.MAV.cs.firmware == Firmwares.Ateryx ||
                    MainV2.comPort.MAV.cs.firmware == Firmwares.ArduRover ||
                    MainV2.comPort.MAV.cs.firmware == Firmwares.ArduCopter2)
                    MainV2.comPort.setMode("Loiter");
            }
            catch
            {
                CustomMessageBox.Show(Strings.CommandFailed, Strings.ERROR);
            }

            ((Control) sender).Enabled = true;
        }

        private void BUT_quickrtl_Click(object sender, EventArgs e)
        {
            try
            {
                ((Control) sender).Enabled = false;
                MainV2.comPort.setMode("RTL");
            }
            catch
            {
                CustomMessageBox.Show(Strings.CommandFailed, Strings.ERROR);
            }

            ((Control) sender).Enabled = true;
        }

        private void BUT_RAWSensor_Click(object sender, EventArgs e)
        {
            Form temp = new RAW_Sensor();
            ThemeManager.ApplyThemeTo(temp);
            temp.Show();
        }

        private void BUT_resetGimbalPos_Click(object sender, EventArgs e)
        {
            trackBarPitch.Value = 0;
            trackBarRoll.Value = 0;
            trackBarYaw.Value = 0;
            MainV2.comPort.setMountConfigure(MAVLink.MAV_MOUNT_MODE.MAVLINK_TARGETING, false, false, false);
            MainV2.comPort.setMountControl((float) trackBarPitch.Value * 100.0f, (float) trackBarRoll.Value * 100.0f,
                (float) trackBarYaw.Value * 100.0f, false);
        }

        private void BUT_resumemis_Click(object sender, EventArgs e)
        {
            if (
                Common.MessageShowAgain("Resume Mission",
                    "Warning this will reprogram your mission, arm and issue a takeoff command (copter)") !=
                DialogResult.OK)
                return;

            try
            {
                if (MainV2.comPort.BaseStream.IsOpen)
                {
                    string lastwp = MainV2.comPort.MAV.cs.lastautowp.ToString();
                    if (lastwp == "-1")
                        lastwp = "1";

                    if (InputBox.Show("Resume at", "Resume mission at waypoint#", ref lastwp) == DialogResult.OK)
                    {
                        int timeout = 0;
                        int lastwpno = int.Parse(lastwp);

                        // scan and check wp's we are skipping
                        // get our target wp
                        var lastwpdata = MainV2.comPort.getWP((ushort) lastwpno);

                        // get all
                        List<Locationwp> cmds = new List<Locationwp>();

                        var wpcount = MainV2.comPort.getWPCount();

                        for (ushort a = 0; a < wpcount; a++)
                        {
                            var wpdata = MainV2.comPort.getWP(a);

                            if (a < lastwpno && a != 0) // allow home
                            {
                                if (wpdata.id != (ushort) MAVLink.MAV_CMD.TAKEOFF)
                                    if (wpdata.id < (ushort) MAVLink.MAV_CMD.LAST)
                                        continue;

                                if (wpdata.id > (ushort) MAVLink.MAV_CMD.DO_LAST)
                                    continue;
                            }

                            cmds.Add(wpdata);
                        }

                        ushort wpno = 0;
                        // upload from wp 0 to end
                        MainV2.comPort.setWPTotal((ushort) (cmds.Count));

                        // add our do commands
                        foreach (var loc in cmds)
                        {
                            MAVLink.MAV_MISSION_RESULT ans = MainV2.comPort.setWP(loc, wpno,
                                (MAVLink.MAV_FRAME) (loc.frame));
                            if (ans != MAVLink.MAV_MISSION_RESULT.MAV_MISSION_ACCEPTED)
                            {
                                CustomMessageBox.Show("Upload wps failed " +
                                                      Enum.Parse(typeof(MAVLink.MAV_CMD), loc.id.ToString()) + " " +
                                                      Enum.Parse(typeof(MAVLink.MAV_MISSION_RESULT), ans.ToString()));
                                return;
                            }

                            wpno++;
                        }

                        MainV2.comPort.setWPACK();

                        FlightPlanner.instance.BUT_read_Click(this, null);

                        // set index back to 1
                        MainV2.comPort.setWPCurrent(MainV2.comPort.MAV.sysid, MainV2.comPort.MAV.compid, 1);

                        if (MainV2.comPort.MAV.cs.firmware == Firmwares.ArduCopter2)
                        {
                            while (MainV2.comPort.MAV.cs.mode.ToLower() != "Guided".ToLower())
                            {
                                MainV2.comPort.setMode("GUIDED");
                                Thread.Sleep(1000);
                                Application.DoEvents();
                                timeout++;

                                if (timeout > 30)
                                {
                                    CustomMessageBox.Show(Strings.ErrorNoResponse, Strings.ERROR);
                                    return;
                                }
                            }

                            timeout = 0;
                            while (!MainV2.comPort.MAV.cs.armed)
                            {
                                MainV2.comPort.doARM(true);
                                Thread.Sleep(1000);
                                Application.DoEvents();
                                timeout++;

                                if (timeout > 30)
                                {
                                    CustomMessageBox.Show(Strings.ErrorNoResponse, Strings.ERROR);
                                    return;
                                }
                            }

                            timeout = 0;
                            while (MainV2.comPort.MAV.cs.alt < (lastwpdata.alt - 2))
                            {
                                if(!MainV2.comPort.doCommand((byte) MainV2.comPort.sysidcurrent,
                                    (byte) MainV2.comPort.compidcurrent, MAVLink.MAV_CMD.TAKEOFF, 0, 0, 0, 0, 0, 0,
                                    lastwpdata.alt)) {
                                        CustomMessageBox.Show(Strings.CommandFailed, Strings.ERROR);
                                        return;
                                    }
                                Thread.Sleep(1000);
                                Application.DoEvents();
                                timeout++;

                                if (timeout > 40)
                                {
                                    CustomMessageBox.Show(Strings.ErrorNoResponse, Strings.ERROR);
                                    return;
                                }
                            }
                        }

                        timeout = 0;
                        while (MainV2.comPort.MAV.cs.mode.ToLower() != "AUTO".ToLower())
                        {
                            MainV2.comPort.setMode("AUTO");
                            Thread.Sleep(1000);
                            Application.DoEvents();
                            timeout++;

                            if (timeout > 30)
                            {
                                CustomMessageBox.Show(Strings.ErrorNoResponse, Strings.ERROR);
                                return;
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                CustomMessageBox.Show(Strings.CommandFailed + "\n" + ex.ToString(), Strings.ERROR);
            }
        }

        private void BUT_select_script_Click(object sender, EventArgs e)
        {
            if (openScriptDialog.ShowDialog() == DialogResult.OK)
            {
                selectedscript = openScriptDialog.FileName;
                BUT_run_script.Visible = BUT_edit_selected.Visible = true;
                labelSelectedScript.Text = "Selected Script: " + selectedscript;
            }
            else
            {
                selectedscript = "";
            }
        }

        private void BUT_setmode_Click(object sender, EventArgs e)
        {
            if (MainV2.comPort.MAV.cs.failsafe)
            {
                if (CustomMessageBox.Show("You are in failsafe, are you sure?", "Failsafe", MessageBoxButtons.YesNo) !=
                    (int) DialogResult.Yes)
                {
                    return;
                }
            }

            MainV2.comPort.setMode(CMB_modes.Text);
        }

        private void BUT_setwp_Click(object sender, EventArgs e)
        {
            try
            {
                ((Control) sender).Enabled = false;
                MainV2.comPort.setWPCurrent(MainV2.comPort.MAV.sysid, MainV2.comPort.MAV.compid,
                    (ushort) CMB_setwp.SelectedIndex); // set nav to
            }
            catch
            {
                CustomMessageBox.Show(Strings.CommandFailed, Strings.ERROR);
            }

            ((Control) sender).Enabled = true;
        }

        private void BUT_speed1_Click(object sender, EventArgs e)
        {
            LogPlayBackSpeed = double.Parse(((MyButton) sender).Tag.ToString(), CultureInfo.InvariantCulture);
            lbl_playbackspeed.Text = "x " + LogPlayBackSpeed;
        }

        private void BUTactiondo_Click(object sender, EventArgs e)
        {


            if (CMB_action.Text == actions.Format_SD_Card.ToString())
            {
                 try
                {
                    //p1 and p2 must be 1 to initate SD card format
                    MainV2.comPort.doCommandInt(MainV2.comPort.MAV.sysid, MainV2.comPort.MAV.compid, MAVLink.MAV_CMD.STORAGE_FORMAT, 1, 1, 0, 0, 0, 0, 0);
                    return;
                }
                catch
                {
                    CustomMessageBox.Show(Strings.CommandFailed, Strings.ERROR);
                    return;
                }
            }


            try
            {
                if (CMB_action.Text == actions.Trigger_Camera.ToString())
                {
                    MainV2.comPort.setDigicamControl(true);
                    return;
                }
            }
            catch
            {
                CustomMessageBox.Show(Strings.CommandFailed, Strings.ERROR);
                return;
            }

            if (CMB_action.Text == actions.Scripting_cmd_stop_and_restart.ToString())
            {
                try
                {
                    MainV2.comPort.doCommandInt(MainV2.comPort.MAV.sysid, MainV2.comPort.MAV.compid, MAVLink.MAV_CMD.SCRIPTING, (int)MAVLink.SCRIPTING_CMD.STOP_AND_RESTART, 0, 0, 0, 0, 0, 0);
                    return;
                }
                catch
                {
                    CustomMessageBox.Show(Strings.CommandFailed, Strings.ERROR);
                    return;
                }
            }

            if (CMB_action.Text == actions.Scripting_cmd_stop.ToString())
            {
                try
                {
                    MainV2.comPort.doCommandInt(MainV2.comPort.MAV.sysid, MainV2.comPort.MAV.compid, MAVLink.MAV_CMD.SCRIPTING, (int)MAVLink.SCRIPTING_CMD.STOP, 0, 0, 0, 0, 0, 0);
                    return;
                }
                catch
                {
                    CustomMessageBox.Show(Strings.CommandFailed, Strings.ERROR);
                    return;
                }
            }

            if (CMB_action.Text == actions.System_Time.ToString())
            {
                var now = DateTime.UtcNow;
                var epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
                ulong time_unix_us = Convert.ToUInt64((now - epoch).TotalMilliseconds * 1000);
                try
                {
                    MainV2.comPort.sendPacket(
                        new MAVLink.mavlink_system_time_t() {time_unix_usec = time_unix_us, time_boot_ms = 0},
                        MainV2.comPort.sysidcurrent, MainV2.comPort.compidcurrent);
                }
                catch
                {
                    CustomMessageBox.Show(Strings.CommandFailed, Strings.ERROR);
                }

                return;
            }

            if (
                CustomMessageBox.Show("Are you sure you want to do " + CMB_action.Text + " ?", "Action",
                    MessageBoxButtons.YesNo) == (int) DialogResult.Yes)
            {
                try
                {
                    ((Control) sender).Enabled = false;

                    int param1 = 0;
                    int param2 = 0;
                    int param3 = 1;

                    // request gyro
                    if (CMB_action.Text == actions.Preflight_Calibration.ToString())
                    {
                        if (MainV2.comPort.MAV.cs.firmware == Firmwares.ArduCopter2)
                            param1 = 1; // gyro
                        param3 = 1; // baro / airspeed
                    }

                    if (CMB_action.Text == actions.Terminate_Flight.ToString())
                    {
                        MainV2.comPort.doCommand(MainV2.comPort.MAV.sysid, MainV2.comPort.MAV.compid, MAVLink.MAV_CMD.DO_FLIGHTTERMINATION, 1.0f, 0, 0, 0, 0, 0, 0);
                        ((Control)sender).Enabled = true;
                        return;
                    }

                    if (CMB_action.Text == actions.Preflight_Reboot_Shutdown.ToString())
                    {
                        MainV2.comPort.doReboot();
                        ((Control) sender).Enabled = true;
                        return;
                    }
                    if (CMB_action.Text == actions.HighLatency_Enable.ToString())
                    {
                        MainV2.comPort.doHighLatency(true);
                        ((Control)sender).Enabled = true;
                        return;
                    }
                    if (CMB_action.Text == actions.HighLatency_Disable.ToString())
                    {
                        MainV2.comPort.doHighLatency(false);
                        ((Control)sender).Enabled = true;
                        return;
                    }
                    if (CMB_action.Text == actions.Toggle_Safety_Switch.ToString())
                    {
                        var target_system = (byte)MainV2.comPort.sysidcurrent;
                        if (target_system == 0) {
                            log.Info("Not toggling safety on sysid 0");
                            return;
                        }
                        var custom_mode = (MainV2.comPort.MAV.cs.sensors_enabled.motor_control && MainV2.comPort.MAV.cs.sensors_enabled.seen) ? 1u : 0u;
                        var mode = new MAVLink.mavlink_set_mode_t() { custom_mode = custom_mode, target_system = target_system };
                        MainV2.comPort.setMode(mode, MAVLink.MAV_MODE_FLAG.SAFETY_ARMED);
                        ((Control)sender).Enabled = true;
                        return;
                    }
                    if (CMB_action.Text == actions.Engine_Start.ToString())
                    {
                        MainV2.comPort.doEngineControl((byte)MainV2.comPort.sysidcurrent, (byte)MainV2.comPort.compidcurrent, true);
                        ((Control)sender).Enabled = true;
                        return;
                    }
                    if (CMB_action.Text == actions.Engine_Stop.ToString())
                    {
                        MainV2.comPort.doEngineControl((byte)MainV2.comPort.sysidcurrent, (byte)MainV2.comPort.compidcurrent, false);
                        ((Control)sender).Enabled = true;
                        return;
                    }

                    if (CMB_action.Text == actions.Battery_Reset.ToString())
                    {
                        param1 = 0xff; // batt 1
                        param2 = 100; // 100%
                        param3 = 0;
                    }

                    MAVLink.MAV_CMD cmd;
                    try
                    {
                        cmd = (MAVLink.MAV_CMD) Enum.Parse(typeof(MAVLink.MAV_CMD), CMB_action.Text.ToUpper(CultureInfo.InvariantCulture));
                    }
                    catch (ArgumentException ex)
                    {
                        cmd = (MAVLink.MAV_CMD) Enum.Parse(typeof(MAVLink.MAV_CMD),
                            "DO_START_" + CMB_action.Text.ToUpper(CultureInfo.InvariantCulture));
                    }

                    if (MainV2.comPort.doCommand(cmd, param1, param2, param3, 0, 0, 0, 0))
                    {

                    }
                    else
                    {
                        CustomMessageBox.Show(Strings.CommandFailed + " " + cmd, Strings.ERROR);
                    }
                }
                catch
                {
                    CustomMessageBox.Show(Strings.CommandFailed, Strings.ERROR);
                }

                ((Control) sender).Enabled = true;
            }
        }

        private void BUTrestartmission_Click(object sender, EventArgs e)
        {
            try
            {
                ((Control) sender).Enabled = false;

                MainV2.comPort.setWPCurrent(MainV2.comPort.MAV.sysid, MainV2.comPort.MAV.compid, 0); // set nav to
            }
            catch
            {
                CustomMessageBox.Show(Strings.CommandFailed, Strings.ERROR);
            }

            ((Control) sender).Enabled = true;
        }

        void cam_camimage(Image camimage)
        {
            hud1.bgimage = camimage;
        }

        private void CB_tuning_CheckedChanged(object sender, EventArgs e)
        {
            if (CB_tuning.Checked)
            {
                splitContainer1.Panel1Collapsed = false;
                ZedGraphTimer.Enabled = true;
                ZedGraphTimer.Start();
                zg1.Visible = true;
                zg1.Refresh();
            }
            else
            {
                splitContainer1.Panel1Collapsed = true;
                ZedGraphTimer.Enabled = false;
                ZedGraphTimer.Stop();
                zg1.Visible = false;
            }

            // Fire the splitContainer1_Panel2_Resize event
            splitContainer1_Panel2_Resize(null, null);
        }

        private void CheckAndBindPreFlightData()
        {
            //this.Invoke((Action) delegate { preFlightChecklist1.BindData(); });
        }

        private void CHK_autopan_CheckedChanged(object sender, EventArgs e)
        {
            Settings.Instance["CHK_autopan"] = CHK_autopan.Checked.ToString();

            //GCSViews.FlightPlanner.instance.autopan = CHK_autopan.Checked;
        }

        void chk_box_tunningCheckedChanged(object sender, EventArgs e)
        {
            ThemeManager.ApplyThemeTo((Control) sender);

            if (((CheckBox) sender).Checked)
            {
                ((CheckBox) sender).BackColor = Color.Green;

                if (list1item == null)
                {
                    if (setupPropertyInfo(ref list1item, ((CheckBox) sender).Name, MainV2.comPort.MAV.cs))
                    {
                        list1.Clear();
                        list1curve = zg1.GraphPane.AddCurve(((CheckBox) sender).Text, list1, Color.Red,
                            SymbolType.None);
                        list1curve.Tag = ((CheckBox) sender).Name;
                        if (tuningwasrightclick)
                        {
                            list1curve.Label.Text += " R";
                            list1curve.IsY2Axis = true;
                            list1curve.YAxisIndex = 0;
                            zg1.GraphPane.Y2Axis.IsVisible = true;
                        }
                    }
                }
                else if (list2item == null)
                {
                    if (setupPropertyInfo(ref list2item, ((CheckBox) sender).Name, MainV2.comPort.MAV.cs))
                    {
                        list2.Clear();
                        list2curve = zg1.GraphPane.AddCurve(((CheckBox) sender).Text, list2, Color.Blue,
                            SymbolType.None);
                        list2curve.Tag = ((CheckBox) sender).Name;
                        if (tuningwasrightclick)
                        {
                            list2curve.Label.Text += " R";
                            list2curve.IsY2Axis = true;
                            list2curve.YAxisIndex = 0;
                            zg1.GraphPane.Y2Axis.IsVisible = true;
                        }
                    }
                }
                else if (list3item == null)
                {
                    if (setupPropertyInfo(ref list3item, ((CheckBox) sender).Name, MainV2.comPort.MAV.cs))
                    {
                        list3.Clear();
                        list3curve = zg1.GraphPane.AddCurve(((CheckBox) sender).Text, list3, Color.Green,
                            SymbolType.None);
                        list3curve.Tag = ((CheckBox) sender).Name;
                        if (tuningwasrightclick)
                        {
                            list3curve.Label.Text += " R";
                            list3curve.IsY2Axis = true;
                            list3curve.YAxisIndex = 0;
                            zg1.GraphPane.Y2Axis.IsVisible = true;
                        }
                    }
                }
                else if (list4item == null)
                {
                    if (setupPropertyInfo(ref list4item, ((CheckBox) sender).Name, MainV2.comPort.MAV.cs))
                    {
                        list4.Clear();
                        list4curve = zg1.GraphPane.AddCurve(((CheckBox) sender).Text, list4, Color.Orange,
                            SymbolType.None);
                        list4curve.Tag = ((CheckBox) sender).Name;
                        if (tuningwasrightclick)
                        {
                            list4curve.Label.Text += " R";
                            list4curve.IsY2Axis = true;
                            list4curve.YAxisIndex = 0;
                            zg1.GraphPane.Y2Axis.IsVisible = true;
                        }
                    }
                }
                else if (list5item == null)
                {
                    if (setupPropertyInfo(ref list5item, ((CheckBox) sender).Name, MainV2.comPort.MAV.cs))
                    {
                        list5.Clear();
                        list5curve = zg1.GraphPane.AddCurve(((CheckBox) sender).Text, list5, Color.Yellow,
                            SymbolType.None);
                        list5curve.Tag = ((CheckBox) sender).Name;
                        if (tuningwasrightclick)
                        {
                            list5curve.Label.Text += " R";
                            list5curve.IsY2Axis = true;
                            list5curve.YAxisIndex = 0;
                            zg1.GraphPane.Y2Axis.IsVisible = true;
                        }
                    }
                }
                else if (list6item == null)
                {
                    if (setupPropertyInfo(ref list6item, ((CheckBox) sender).Name, MainV2.comPort.MAV.cs))
                    {
                        list6.Clear();
                        list6curve = zg1.GraphPane.AddCurve(((CheckBox) sender).Text, list6, Color.Magenta,
                            SymbolType.None);
                        list6curve.Tag = ((CheckBox) sender).Name;
                        if (tuningwasrightclick)
                        {
                            list6curve.Label.Text += " R";
                            list6curve.IsY2Axis = true;
                            list6curve.YAxisIndex = 0;
                            zg1.GraphPane.Y2Axis.IsVisible = true;
                        }
                    }
                }
                else if (list7item == null)
                {
                    if (setupPropertyInfo(ref list7item, ((CheckBox) sender).Name, MainV2.comPort.MAV.cs))
                    {
                        list7.Clear();
                        list7curve = zg1.GraphPane.AddCurve(((CheckBox) sender).Text, list7, Color.Purple,
                            SymbolType.None);
                        list7curve.Tag = ((CheckBox) sender).Name;
                        if (tuningwasrightclick)
                        {
                            list7curve.Label.Text += " R";
                            list7curve.IsY2Axis = true;
                            list7curve.YAxisIndex = 0;
                            zg1.GraphPane.Y2Axis.IsVisible = true;
                        }
                    }
                }
                else if (list8item == null)
                {
                    if (setupPropertyInfo(ref list8item, ((CheckBox) sender).Name, MainV2.comPort.MAV.cs))
                    {
                        list8.Clear();
                        list8curve = zg1.GraphPane.AddCurve(((CheckBox) sender).Text, list8, Color.LimeGreen,
                            SymbolType.None);
                        list8curve.Tag = ((CheckBox) sender).Name;
                        if (tuningwasrightclick)
                        {
                            list8curve.Label.Text += " R";
                            list8curve.IsY2Axis = true;
                            list8curve.YAxisIndex = 0;
                            zg1.GraphPane.Y2Axis.IsVisible = true;
                        }
                    }
                }
                else if (list9item == null)
                {
                    if (setupPropertyInfo(ref list9item, ((CheckBox) sender).Name, MainV2.comPort.MAV.cs))
                    {
                        list9.Clear();
                        list9curve = zg1.GraphPane.AddCurve(((CheckBox) sender).Text, list9, Color.Cyan,
                            SymbolType.None);
                        list9curve.Tag = ((CheckBox) sender).Name;
                        if (tuningwasrightclick)
                        {
                            list9curve.Label.Text += " R";
                            list9curve.IsY2Axis = true;
                            list9curve.YAxisIndex = 0;
                            zg1.GraphPane.Y2Axis.IsVisible = true;
                        }
                    }
                }
                else if (list10item == null)
                {
                    if (setupPropertyInfo(ref list10item, ((CheckBox) sender).Name, MainV2.comPort.MAV.cs))
                    {
                        list10.Clear();
                        list10curve = zg1.GraphPane.AddCurve(((CheckBox) sender).Text, list10, Color.Violet,
                            SymbolType.None);
                        list10curve.Tag = ((CheckBox) sender).Name;
                        if (tuningwasrightclick)
                        {
                            list10curve.Label.Text += " R";
                            list10curve.IsY2Axis = true;
                            list10curve.YAxisIndex = 0;
                            zg1.GraphPane.Y2Axis.IsVisible = true;
                        }
                    }
                }
                else if (list11item == null)
                {
                    if (setupPropertyInfo(ref list11item, ((CheckBox) sender).Name, MainV2.comPort.MAV.cs))
                    {
                        list11.Clear();
                        list11curve = zg1.GraphPane.AddCurve(((CheckBox) sender).Text, list11, Color.Violet,
                            SymbolType.None);
                        list11curve.Tag = ((CheckBox) sender).Name;
                        if (tuningwasrightclick)
                        {
                            list11curve.Label.Text += " R";
                            list11curve.IsY2Axis = true;
                            list11curve.YAxisIndex = 0;
                            zg1.GraphPane.Y2Axis.IsVisible = true;
                        }
                    }
                }
                else if (list12item == null)
                {
                    if (setupPropertyInfo(ref list12item, ((CheckBox) sender).Name, MainV2.comPort.MAV.cs))
                    {
                        list12.Clear();
                        list12curve = zg1.GraphPane.AddCurve(((CheckBox) sender).Text, list12, Color.Violet,
                            SymbolType.None);
                        list12curve.Tag = ((CheckBox) sender).Name;
                        if (tuningwasrightclick)
                        {
                            list12curve.Label.Text += " R";
                            list12curve.IsY2Axis = true;
                            list12curve.YAxisIndex = 0;
                            zg1.GraphPane.Y2Axis.IsVisible = true;
                        }
                    }
                }
                else if (list13item == null)
                {
                    if (setupPropertyInfo(ref list13item, ((CheckBox) sender).Name, MainV2.comPort.MAV.cs))
                    {
                        list13.Clear();
                        list13curve = zg1.GraphPane.AddCurve(((CheckBox) sender).Text, list13, Color.Violet,
                            SymbolType.None);
                        list13curve.Tag = ((CheckBox) sender).Name;
                        if (tuningwasrightclick)
                        {
                            list13curve.Label.Text += " R";
                            list13curve.IsY2Axis = true;
                            list13curve.YAxisIndex = 0;
                            zg1.GraphPane.Y2Axis.IsVisible = true;
                        }
                    }
                }
                else if (list14item == null)
                {
                    if (setupPropertyInfo(ref list14item, ((CheckBox) sender).Name, MainV2.comPort.MAV.cs))
                    {
                        list14.Clear();
                        list14curve = zg1.GraphPane.AddCurve(((CheckBox) sender).Text, list14, Color.Violet,
                            SymbolType.None);
                        list14curve.Tag = ((CheckBox) sender).Name;
                        if (tuningwasrightclick)
                        {
                            list14curve.Label.Text += " R";
                            list14curve.IsY2Axis = true;
                            list14curve.YAxisIndex = 0;
                            zg1.GraphPane.Y2Axis.IsVisible = true;
                        }
                    }
                }
                else if (list15item == null)
                {
                    if (setupPropertyInfo(ref list15item, ((CheckBox) sender).Name, MainV2.comPort.MAV.cs))
                    {
                        list15.Clear();
                        list15curve = zg1.GraphPane.AddCurve(((CheckBox) sender).Text, list15, Color.Violet,
                            SymbolType.None);
                        list15curve.Tag = ((CheckBox) sender).Name;
                        if (tuningwasrightclick)
                        {
                            list15curve.Label.Text += " R";
                            list15curve.IsY2Axis = true;
                            list15curve.YAxisIndex = 0;
                            zg1.GraphPane.Y2Axis.IsVisible = true;
                        }
                    }
                }
                else if (list16item == null)
                {
                    if (setupPropertyInfo(ref list16item, ((CheckBox) sender).Name, MainV2.comPort.MAV.cs))
                    {
                        list16.Clear();
                        list16curve = zg1.GraphPane.AddCurve(((CheckBox) sender).Text, list16, Color.Violet,
                            SymbolType.None);
                        list16curve.Tag = ((CheckBox) sender).Name;
                        if (tuningwasrightclick)
                        {
                            list16curve.Label.Text += " R";
                            list16curve.IsY2Axis = true;
                            list16curve.YAxisIndex = 0;
                            zg1.GraphPane.Y2Axis.IsVisible = true;
                        }
                    }
                }
                else if (list17item == null)
                {
                    if (setupPropertyInfo(ref list17item, ((CheckBox) sender).Name, MainV2.comPort.MAV.cs))
                    {
                        list17.Clear();
                        list17curve = zg1.GraphPane.AddCurve(((CheckBox) sender).Text, list17, Color.Violet,
                            SymbolType.None);
                        list17curve.Tag = ((CheckBox) sender).Name;
                        if (tuningwasrightclick)
                        {
                            list17curve.Label.Text += " R";
                            list17curve.IsY2Axis = true;
                            list17curve.YAxisIndex = 0;
                            zg1.GraphPane.Y2Axis.IsVisible = true;
                        }
                    }
                }
                else if (list18item == null)
                {
                    if (setupPropertyInfo(ref list18item, ((CheckBox) sender).Name, MainV2.comPort.MAV.cs))
                    {
                        list18.Clear();
                        list18curve = zg1.GraphPane.AddCurve(((CheckBox) sender).Text, list18, Color.Violet,
                            SymbolType.None);
                        list18curve.Tag = ((CheckBox) sender).Name;
                        if (tuningwasrightclick)
                        {
                            list18curve.Label.Text += " R";
                            list18curve.IsY2Axis = true;
                            list18curve.YAxisIndex = 0;
                            zg1.GraphPane.Y2Axis.IsVisible = true;
                        }
                    }
                }
                else if (list19item == null)
                {
                    if (setupPropertyInfo(ref list19item, ((CheckBox) sender).Name, MainV2.comPort.MAV.cs))
                    {
                        list19.Clear();
                        list19curve = zg1.GraphPane.AddCurve(((CheckBox) sender).Text, list19, Color.Violet,
                            SymbolType.None);
                        list19curve.Tag = ((CheckBox) sender).Name;
                        if (tuningwasrightclick)
                        {
                            list19curve.Label.Text += " R";
                            list19curve.IsY2Axis = true;
                            list19curve.YAxisIndex = 0;
                            zg1.GraphPane.Y2Axis.IsVisible = true;
                        }
                    }
                }
                else if (list20item == null)
                {
                    if (setupPropertyInfo(ref list20item, ((CheckBox) sender).Name, MainV2.comPort.MAV.cs))
                    {
                        list20.Clear();
                        list20curve = zg1.GraphPane.AddCurve(((CheckBox) sender).Text, list20, Color.Violet,
                            SymbolType.None);
                        list20curve.Tag = ((CheckBox) sender).Name;
                        if (tuningwasrightclick)
                        {
                            list20curve.Label.Text += " R";
                            list20curve.IsY2Axis = true;
                            list20curve.YAxisIndex = 0;
                            zg1.GraphPane.Y2Axis.IsVisible = true;
                        }
                    }
                }
                else
                {
                    CustomMessageBox.Show("Max 20 at a time.");
                    ((CheckBox) sender).Checked = false;
                }

                string selected = "";
                try
                {
                    foreach (var curve in zg1.GraphPane.CurveList)
                    {
                        string curve_name = curve.Tag.ToString();
                        if (curve_name.Contains("customfield"))
                        {
                            curve_name += ((CheckBox)sender).Text;
                        }
                        selected = selected + curve_name + "|";
                    }
                }
                catch
                {
                }

                Settings.Instance["Tuning_Graph_Selected"] = selected;
            }
            else
            {
                ((CheckBox) sender).BackColor = Color.Transparent;

                // reset old stuff
                if (list1item != null && list1item.Name == ((CheckBox) sender).Name)
                {
                    list1item = null;
                    zg1.GraphPane.CurveList.Remove(list1curve);
                }

                if (list2item != null && list2item.Name == ((CheckBox) sender).Name)
                {
                    list2item = null;
                    zg1.GraphPane.CurveList.Remove(list2curve);
                }

                if (list3item != null && list3item.Name == ((CheckBox) sender).Name)
                {
                    list3item = null;
                    zg1.GraphPane.CurveList.Remove(list3curve);
                }

                if (list4item != null && list4item.Name == ((CheckBox) sender).Name)
                {
                    list4item = null;
                    zg1.GraphPane.CurveList.Remove(list4curve);
                }

                if (list5item != null && list5item.Name == ((CheckBox) sender).Name)
                {
                    list5item = null;
                    zg1.GraphPane.CurveList.Remove(list5curve);
                }

                if (list6item != null && list6item.Name == ((CheckBox) sender).Name)
                {
                    list6item = null;
                    zg1.GraphPane.CurveList.Remove(list6curve);
                }

                if (list7item != null && list7item.Name == ((CheckBox) sender).Name)
                {
                    list7item = null;
                    zg1.GraphPane.CurveList.Remove(list7curve);
                }

                if (list8item != null && list8item.Name == ((CheckBox) sender).Name)
                {
                    list8item = null;
                    zg1.GraphPane.CurveList.Remove(list8curve);
                }

                if (list9item != null && list9item.Name == ((CheckBox) sender).Name)
                {
                    list9item = null;
                    zg1.GraphPane.CurveList.Remove(list9curve);
                }

                if (list10item != null && list10item.Name == ((CheckBox) sender).Name)
                {
                    list10item = null;
                    zg1.GraphPane.CurveList.Remove(list10curve);
                }

                if (list11item != null && list11item.Name == ((CheckBox) sender).Name)
                {
                    list11item = null;
                    zg1.GraphPane.CurveList.Remove(list11curve);
                }

                if (list12item != null && list12item.Name == ((CheckBox) sender).Name)
                {
                    list12item = null;
                    zg1.GraphPane.CurveList.Remove(list12curve);
                }

                if (list13item != null && list13item.Name == ((CheckBox) sender).Name)
                {
                    list13item = null;
                    zg1.GraphPane.CurveList.Remove(list13curve);
                }

                if (list14item != null && list14item.Name == ((CheckBox) sender).Name)
                {
                    list14item = null;
                    zg1.GraphPane.CurveList.Remove(list14curve);
                }

                if (list15item != null && list15item.Name == ((CheckBox) sender).Name)
                {
                    list15item = null;
                    zg1.GraphPane.CurveList.Remove(list15curve);
                }

                if (list16item != null && list16item.Name == ((CheckBox) sender).Name)
                {
                    list16item = null;
                    zg1.GraphPane.CurveList.Remove(list16curve);
                }

                if (list17item != null && list17item.Name == ((CheckBox) sender).Name)
                {
                    list17item = null;
                    zg1.GraphPane.CurveList.Remove(list17curve);
                }

                if (list18item != null && list18item.Name == ((CheckBox) sender).Name)
                {
                    list18item = null;
                    zg1.GraphPane.CurveList.Remove(list18curve);
                }

                if (list19item != null && list19item.Name == ((CheckBox) sender).Name)
                {
                    list19item = null;
                    zg1.GraphPane.CurveList.Remove(list19curve);
                }

                if (list20item != null && list20item.Name == ((CheckBox) sender).Name)
                {
                    list20item = null;
                    zg1.GraphPane.CurveList.Remove(list20curve);
                }
            }
        }

        void chk_box_hud_UserItem_CheckedChanged(object sender, EventArgs e)
        {
            CheckBox checkbox = (CheckBox) sender;

            if (checkbox.Checked)
            {
                checkbox.BackColor = Color.Green;

                HUD.Custom cust = new HUD.Custom();
                HUD.Custom.src = MainV2.comPort.MAV.cs;

                string prefix = checkbox.Text + ": ";
                if (Settings.Instance["hud1_useritem_" + checkbox.Name] != null)
                    prefix = Settings.Instance["hud1_useritem_" + checkbox.Name];

                if (DialogResult.Cancel == InputBox.Show("Hud Header", "Please enter your item prefix", ref prefix))
                {
                    checkbox.Checked = false;
                    return;
                }

                Settings.Instance["hud1_useritem_" + checkbox.Name] = prefix;

                cust.Header = prefix;

                addHudUserItem(ref cust, checkbox.Name);
            }
            else
            {
                checkbox.BackColor = Color.Transparent;

                if (hud1.CustomItems.ContainsKey(checkbox.Name))
                    hud1.CustomItems.Remove(checkbox.Name);

                Settings.Instance.Remove("hud1_useritem_" + checkbox.Name);
                hud1.Invalidate();
            }
        }

        void chk_box_quickview_CheckedChanged(object sender, EventArgs e)
        {
            CheckBox checkbox = (CheckBox) sender;

            if (checkbox.Checked)
            {
                // save settings
                Settings.Instance[((QuickView) checkbox.Tag).Name] = checkbox.Name;

                // set description
                string desc = checkbox.Name;
                ((QuickView) checkbox.Tag).Tag = desc;

                desc = MainV2.comPort.MAV.cs.GetNameandUnit(desc);

                ((QuickView) checkbox.Tag).desc = desc;

                // set databinding for value
                ((QuickView) checkbox.Tag).DataBindings.Clear();

                var b = new Binding("number", bindingSourceQuickTab, checkbox.Name,
                    true);
                b.Format += new ConvertEventHandler(BindingTypeToNumber);
                b.Parse += new ConvertEventHandler(NumberToBindingType);

                ((QuickView) checkbox.Tag).DataBindings.Add(b);

                // close selection form
                ((Form) checkbox.Parent).Close();
            }
        }

        private void NumberToBindingType(object sender, ConvertEventArgs e)
        {

        }

        private void BindingTypeToNumber(object sender, ConvertEventArgs e)
        {
            if(e.Value is Boolean)
            {
                var ans = (bool)e.Value;
                e.Value = ans ? 1 : 0;
            }
        }

        void chk_log_CheckedChanged(object sender, EventArgs e)
        {
            if (((CheckBox) sender).Checked)
            {
                zg1.GraphPane.YAxis.Type = AxisType.Log;
            }
            else
            {
                zg1.GraphPane.YAxis.Type = AxisType.Linear;
            }
        }

        private void CMB_modes_Click(object sender, EventArgs e)
        {
            string current_value = CMB_modes.Text;
            CMB_modes.DataSource = ArduPilot.Common.getModesList(MainV2.comPort.MAV.cs.firmware);
            CMB_modes.ValueMember = "Key";
            CMB_modes.DisplayMember = "Value";
            CMB_modes.Text = current_value;
        }

        private void CMB_setwp_Click(object sender, EventArgs e)
        {
            CMB_setwp.Items.Clear();

            CMB_setwp.Items.Add("0 (Home)");

            int max = 0;

            if (MainV2.comPort.MAV.param["CMD_TOTAL"] != null)
            {
                int wps = int.Parse(MainV2.comPort.MAV.param["CMD_TOTAL"].ToString());

                max = Math.Max(max, wps);
            }

            if (MainV2.comPort.MAV.param["WP_TOTAL"] != null)
            {
                int wps = int.Parse(MainV2.comPort.MAV.param["WP_TOTAL"].ToString());

                max = Math.Max(max, wps);
            }

            if (MainV2.comPort.MAV.param["MIS_TOTAL"] != null)
            {
                int wps = int.Parse(MainV2.comPort.MAV.param["MIS_TOTAL"].ToString());

                max = Math.Max(max, wps);
            }

            if (MainV2.comPort.MAV.wps.Count > 0)
            {
                int wps = MainV2.comPort.MAV.wps.Count;

                max = Math.Max(max, wps);
            }

            for (int z = 1; z <= max; z++)
            {
                CMB_setwp.Items.Add(z.ToString());
            }
        }

        private void customizeToolStripMenuItem_Click(object sender, EventArgs e)
        {
            using (Form customForm = new Form())
            {
                CheckedListBox left = new CheckedListBox();
                left.Dock = DockStyle.Fill;
                left.CheckOnClick = true;

                customForm.Controls.Add(left);

                string tabs = Settings.Instance["tabcontrolactions"];

                // setup default if doesnt exist
                if (tabs == null)
                {
                    saveTabControlActions();
                    tabs = Settings.Instance["tabcontrolactions"];
                }

                string[] tabarray = tabs.Split(';').Distinct().ToArray();

                foreach (TabPage tabPage in TabListOriginal)
                {
                    if((TabListDisplay.ContainsKey(tabPage.Name) && TabListDisplay[tabPage.Name] == true) || !TabListDisplay.ContainsKey(tabPage.Name))
                    {
                        if (tabarray.Contains(tabPage.Name))
                            left.Items.Add(tabPage.Name, true);
                        else
                            left.Items.Add(tabPage.Name, false);
                    }
                }

                ThemeManager.ApplyThemeTo(customForm);

                customForm.ShowDialog();

                string answer = "";
                foreach (var tabPage in left.CheckedItems)
                {
                    answer += tabPage + ";";
                }

                Settings.Instance["tabcontrolactions"] = answer;

                updateDisplayView();
            }
        }

        private void deleteToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (CurrentGMapMarker == null || !(CurrentGMapMarker is GMapMarkerPOI))
                return;

            POI.POIDelete((GMapMarkerPOI) CurrentGMapMarker);
        }

        void dropout_FormClosed(object sender, FormClosedEventArgs e)
        {
            (sender as Form).SaveStartupLocation();
            //GetFormFromGuid(GetOrCreateGuid("fd_hud_guid")).Controls.Add(hud1);
            ((sender as Form).Tag as Control).Controls.Add(hud1);
            //SubMainLeft.Panel1.Controls.Add(hud1);
            if (hud1.Parent == SubMainLeft.Panel1)
                SubMainLeft.Panel1Collapsed = false;
            huddropout = false;
        }

        void dropout_Resize(object sender, EventArgs e)
        {
            if (huddropoutresize)
                return;

            huddropoutresize = true;

            int hudh = hud1.Height;
            int formh = ((Form) sender).Height - 30;

            if (((Form) sender).Height < hudh)
            {
                if (((Form) sender).WindowState == FormWindowState.Maximized)
                {
                    Point tl = ((Form) sender).DesktopLocation;
                    ((Form) sender).WindowState = FormWindowState.Normal;
                    ((Form) sender).Location = tl;
                }

                ((Form) sender).Width = (int) (formh * (hud1.SixteenXNine ? 1.777f : 1.333f));
                ((Form) sender).Height = formh + 20;
            }

            hud1.Refresh();
            huddropoutresize = false;
        }

        private void dropOutToolStripMenuItem_Click(object sender, EventArgs e)
        {
        }

        private void FlightData_FormClosing(object sender, FormClosingEventArgs e)
        {
            threadrun = false;

            DateTime end = DateTime.Now.AddSeconds(5);

            if (thisthread == null)
                return;

            while (thisthread.IsAlive && DateTime.Now < end)
            {
                Application.DoEvents();
            }

            // you cannot call join on the main thread, and invoke on the thread. as it just hangs on the invoke.

            //thisthread.Join();
        }

        private void FlightData_Load(object sender, EventArgs e)
        {
            POI.POIModified += POI_POIModified;

            if (!Settings.Instance.ContainsKey("ShowNoFly") || Settings.Instance.GetBoolean("ShowNoFly"))
                NoFly.NoFly.NoFlyEvent += NoFly_NoFlyEvent;

            TRK_zoom.Minimum = gMapControl1.MapProvider.MinZoom;
            TRK_zoom.Maximum = 24;
            TRK_zoom.Value = (float) gMapControl1.Zoom;

            gMapControl1.EmptyTileColor = Color.Gray;

            Zoomlevel.Minimum = gMapControl1.MapProvider.MinZoom;
            Zoomlevel.Maximum = 24;
            Zoomlevel.Value = Convert.ToDecimal(gMapControl1.Zoom);


            var mnt_mode_paramnames = new List<string> { "MNT1_DEFLT_MODE", "MNT_DEFLT_MODE", "MNT_MODE" };
            foreach (var name in mnt_mode_paramnames)
            {
                var item = ParameterMetaDataRepository.GetParameterOptionsInt(name, MainV2.comPort.MAV.cs.firmware.ToString());
                if (item.Count > 0)
                {
                    CMB_mountmode.DataSource = item;
                    CMB_mountmode.DisplayMember = "Value";
                    CMB_mountmode.ValueMember = "Key";
                    break;
                }
            }

            if (Settings.Instance["CHK_autopan"] != null)
                CHK_autopan.Checked = Settings.Instance.GetBoolean("CHK_autopan");

            if (Settings.Instance.ContainsKey("HudSwap") && Settings.Instance["HudSwap"] == "true")
                SwapHud1AndMap();

            if (Settings.Instance.ContainsKey("FlightSplitter"))
            {
                MainH.SplitterDistance = Settings.Instance.GetInt32("FlightSplitter");
            }

            if (Settings.Instance.ContainsKey("russian_hud"))
            {
                hud1.Russian = Settings.Instance.GetBoolean("russian_hud");
            }

            //Remove it later, do not need
            groundColorToolStripMenuItem.Checked = Settings.Instance.GetBoolean("groundColorToolStripMenuItem");
            groundColorToolStripMenuItem_Click(null, null);

            hud1.doResize();

            prop = new Propagation(gMapControl1);

            splitContainer1.Panel1Collapsed = true;

            try
            {
                thisthread = new Thread(mainloop);
                thisthread.Name = "FD Mainloop";
                thisthread.IsBackground = true;
                thisthread.Start();
            }
            catch (NotSupportedException)
            {
                mainloop();
            }
        }

        private void FlightData_ParentChanged(object sender, EventArgs e)
        {
            if (MainV2.cam != null)
            {
                MainV2.cam.camimage += cam_camimage;
            }

            // QUAD
            if (MainV2.comPort.MAV.param.ContainsKey("WP_SPEED_MAX"))
            {
                try
                {
                    modifyandSetSpeed.Value = (decimal) ((float) MainV2.comPort.MAV.param["WP_SPEED_MAX"] / 100.0);
                }
                catch
                {
                    modifyandSetSpeed.Enabled = false;
                }
            }
            // plane 3.7 and below with airspeed, uses ARSPD_ENABLE:
            else if ((MainV2.comPort.MAV.param.ContainsKey("TRIM_ARSPD_CM") &&
                      MainV2.comPort.MAV.param.ContainsKey("ARSPD_ENABLE")
                      && MainV2.comPort.MAV.param.ContainsKey("ARSPD_USE") &&
                      (float) MainV2.comPort.MAV.param["ARSPD_ENABLE"] == 1
                      && (float) MainV2.comPort.MAV.param["ARSPD_USE"] == 1) ||
                     // plane 3.8 and above with airspeed as per plane 3.7 to plane 3.8 migration wiki page, no longer uses ARSPD_ENABLE, uses ARSPD_TYPE instead:
                     (MainV2.comPort.MAV.param.ContainsKey("TRIM_ARSPD_CM") &&
                      MainV2.comPort.MAV.param.ContainsKey("ARSPD_TYPE")
                      && MainV2.comPort.MAV.param.ContainsKey("ARSPD_USE") &&
                      (float) MainV2.comPort.MAV.param["ARSPD_TYPE"] > 0
                      && (float) MainV2.comPort.MAV.param["ARSPD_USE"] == 1))
            {
                try
                {
                    modifyandSetSpeed.Value = (decimal) ((float) MainV2.comPort.MAV.param["TRIM_ARSPD_CM"] / 100.0);
                }
                catch
                {
                    modifyandSetSpeed.Enabled = false;
                }
            } // plane without airspeed
            else if (MainV2.comPort.MAV.param.ContainsKey("TRIM_THROTTLE") &&
                     MainV2.comPort.MAV.param.ContainsKey("ARSPD_USE")
                     && (float) MainV2.comPort.MAV.param["ARSPD_USE"] == 0)
            {
                try
                {
                    modifyandSetSpeed.Value = (decimal) (float) MainV2.comPort.MAV.param["TRIM_THROTTLE"];
                }
                catch
                {
                    modifyandSetSpeed.Enabled = false;
                }

                // percent
                modifyandSetSpeed.ButtonText = Strings.ChangeThrottle;
            }

            try
            {
                if (MainV2.comPort.MAV.param.ContainsKey("LOITER_RAD"))
                    modifyandSetLoiterRad.Value =
                        (decimal) ((float) MainV2.comPort.MAV.param["LOITER_RAD"] * CurrentState.multiplierdist);
            }
            catch
            {
                modifyandSetLoiterRad.Enabled = false;
            }

            try
            {
                if (MainV2.comPort.MAV.param.ContainsKey("WP_LOITER_RAD"))
                {
                    modifyandSetLoiterRad.Value =
                        (decimal) ((float) MainV2.comPort.MAV.param["WP_LOITER_RAD"] * CurrentState.multiplierdist);
                }
            }
            catch
            {
                modifyandSetLoiterRad.Enabled = false;
            }
        }

        private void FlightData_Resize(object sender, EventArgs e)
        {
            //Gspeed;
            //Galt;
            //Gheading;
            //attitudeIndicatorInstrumentControl1;
        }

        private void flightPlannerToolStripMenuItem_Click(object sender, EventArgs e)
        {
            foreach (Control ctl in splitContainer1.Panel2.Controls)
            {
                ctl.Visible = false;
            }

            foreach (MainSwitcher.Screen sc in MainV2.View.screens)
            {
                if (sc.Name == "FlightPlanner")
                {
                    MyButton but = new MyButton
                    {
                        Location = new Point(splitContainer1.Panel2.Width / 2, 0),
                        Text = "Close"
                    };
                    but.Click += but_Click;

                    splitContainer1.Panel2.Controls.Add(but);
                    splitContainer1.Panel2.Controls.Add(sc.Control);
                    ThemeManager.ApplyThemeTo(sc.Control);
                    ThemeManager.ApplyThemeTo(this);

                    sc.Control.Dock = DockStyle.Fill;
                    sc.Control.Visible = true;

                    if (sc.Control is IActivate)
                    {
                        ((IActivate) (sc.Control)).Activate();
                    }

                    but.BringToFront();
                    break;
                }
            }
        }

        private void flyToHereAltToolStripMenuItem_Click(object sender, EventArgs e)
        {
            string alt = "100";
            MAVLink.MAV_FRAME frame = MAVLink.MAV_FRAME.GLOBAL_RELATIVE_ALT;

            if (MainV2.comPort.MAV.cs.firmware == Firmwares.ArduCopter2)
            {
                alt = (10 * CurrentState.multiplieralt).ToString("0");
            }
            else
            {
                alt = (100 * CurrentState.multiplieralt).ToString("0");
            }

            if (Settings.Instance.ContainsKey("guided_alt"))
                alt = Settings.Instance["guided_alt"];
            if (Settings.Instance.ContainsKey("guided_alt_frame"))
                frame = (MAVLink.MAV_FRAME)byte.Parse(Settings.Instance["guided_alt_frame"]);

            if (DialogResult.Cancel == AltInputBox.Show("Enter Alt", "Enter Guided Mode Alt", ref alt, ref frame))
                return;

            Settings.Instance["guided_alt"] = alt;
            Settings.Instance["guided_alt_frame"] = ((byte)frame).ToString();

            int intalt = (int) (100 * CurrentState.multiplieralt);
            if (!int.TryParse(alt, out intalt))
            {
                CustomMessageBox.Show("Bad Alt");
                return;
            }

            MainV2.comPort.MAV.GuidedMode.z = intalt / CurrentState.multiplieralt;
            MainV2.comPort.MAV.GuidedMode.frame = (byte) frame;

            if (MainV2.comPort.MAV.cs.mode == "Guided")
            {
                MainV2.comPort.setGuidedModeWP(new Locationwp
                {
                    alt = MainV2.comPort.MAV.GuidedMode.z,
                    lat = MainV2.comPort.MAV.GuidedMode.x / 1e7,
                    lng = MainV2.comPort.MAV.GuidedMode.y / 1e7,
                    frame = (byte)frame
                });
            }
        }

        private void gimbalTrackbar_Scroll(object sender, EventArgs e)
        {
            MainV2.comPort.setMountControl((float) trackBarPitch.Value * 100.0f, (float) trackBarRoll.Value * 100.0f,
                (float) trackBarYaw.Value * 100.0f, false);
        }

        private void gMapControl1_Click(object sender, EventArgs e)
        {
        }

        private void gMapControl1_MouseDown(object sender, MouseEventArgs e)
        {
            MouseDownStart = gMapControl1.FromLocalToLatLng(e.X, e.Y);
            Console.WriteLine("gMapControl1_MouseDown "+ MouseDownStart);

            if (ModifierKeys == Keys.Control)
            {
                goHereToolStripMenuItem_Click(null, null);
                return;
            }

            if (CurrentGMapMarker is GMapMarkerADSBPlane)
            {
                var marker = CurrentGMapMarker as GMapMarkerADSBPlane;
                if (marker.Tag is adsb.PointLatLngAltHdg)
                {
                    var plla = marker.Tag as adsb.PointLatLngAltHdg;
                    plla.DisplayICAO = !plla.DisplayICAO;
                }
            }
        }

        private void gMapControl1_MouseLeave(object sender, EventArgs e)
        {
            if (marker != null)
            {
                try
                {
                    if (routes.Markers.Contains(marker))
                        routes.Markers.Remove(marker);
                }
                catch
                {
                }
            }
        }

        private void gMapControl1_MouseMove(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                PointLatLng point = gMapControl1.FromLocalToLatLng(e.X, e.Y);

                double latdif = MouseDownStart.Lat - point.Lat;
                double lngdif = MouseDownStart.Lng - point.Lng;

                gMapControl1.Position = new PointLatLng(center.Position.Lat + latdif,
                    center.Position.Lng + lngdif);
            }
            else
            {
                // setup a ballon with home distance
                if (marker != null)
                {
                    if (routes.Markers.Contains(marker))
                        routes.Markers.Remove(marker);
                }

                if (Settings.Instance.GetBoolean("CHK_disttohomeflightdata") != false)
                {
                    PointLatLng point = gMapControl1.FromLocalToLatLng(e.X, e.Y);

                    marker = new GMapMarkerRect(point);
                    marker.ToolTip = new GMapToolTip(marker);
                    marker.ToolTipMode = MarkerTooltipMode.Always;
                    marker.ToolTipText = "Dist to Home: " +
                                         ((gMapControl1.MapProvider.Projection.GetDistance(point,
                                              MainV2.comPort.MAV.cs.HomeLocation.Point()) * 1000) *
                                          CurrentState.multiplierdist).ToString("0");

                    routes.Markers.Add(marker);
                }
            }
        }

        void gMapControl1_OnMapZoomChanged()
        {
            try
            {
                // Exception System.Runtime.InteropServices.SEHException: External component has thrown an exception.
                TRK_zoom.Value = (float) gMapControl1.Zoom;
                Zoomlevel.Value = Convert.ToDecimal(gMapControl1.Zoom);
            }
            catch
            {
            }

            center.Position = gMapControl1.Position;
        }

        void gMapControl1_OnMarkerEnter(GMapMarker item)
        {
            CurrentGMapMarker = item;
        }

        void gMapControl1_OnMarkerLeave(GMapMarker item)
        {
            CurrentGMapMarker = null;
        }

        private void gMapControl1_OnPositionChanged(PointLatLng point)
        {
            center.Position = point;

            UpdateOverlayVisibility();
        }

        private void gMapControl1_Resize(object sender, EventArgs e)
        {
            gMapControl1.Zoom = gMapControl1.Zoom + 0.01;
        }

        private void goHereToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (!MainV2.comPort.BaseStream.IsOpen)
            {
                CustomMessageBox.Show(Strings.PleaseConnect, Strings.ERROR);
                return;
            }

            if (MainV2.comPort.MAV.GuidedMode.z == 0f)
            {
                flyToHereAltToolStripMenuItem_Click(null, null);

                if (MainV2.comPort.MAV.GuidedMode.z == 0f)
                    return;
            }

            if (MouseDownStart.Lat == 0.0 || MouseDownStart.Lng == 0.0)
            {
                CustomMessageBox.Show(Strings.BadCoords, Strings.ERROR);
                return;
            }

            Locationwp gotohere = new Locationwp();

            gotohere.id = (ushort) MAVLink.MAV_CMD.WAYPOINT;
            gotohere.alt = MainV2.comPort.MAV.GuidedMode.z; // back to m
            gotohere.lat = (MouseDownStart.Lat);
            gotohere.lng = (MouseDownStart.Lng);
            gotohere.frame = MainV2.comPort.MAV.GuidedMode.frame;

            try
            {
                MainV2.comPort.setGuidedModeWP(gotohere);
            }
            catch (Exception ex)
            {
                CustomMessageBox.Show(Strings.CommandFailed + ex.Message, Strings.ERROR);
            }
        }

        private void groundColorToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (groundColorToolStripMenuItem.Checked)
            {
                // brown
                hud1.groundColor1 = Color.FromArgb(147, 78, 1);
                hud1.groundColor2 = Color.FromArgb(60, 33, 4);
            }
            else
            {
                // green
                hud1.groundColor1 = Color.FromArgb(0x9b, 0xb8, 0x24);
                hud1.groundColor2 = Color.FromArgb(0x41, 0x4f, 0x07);
            }

            Settings.config["groundColorToolStripMenuItem"] = groundColorToolStripMenuItem.Checked.ToString();
        }

        private void Gspeed_DoubleClick(object sender, EventArgs e)
        {
            string max = "60";
            if (DialogResult.OK == InputBox.Show("Enter Max Speed", "Enter Max Speed", ref max))
            {
                Gspeed.MaxValue = float.Parse(max);
                Settings.Instance["GspeedMAX"] = Gspeed.MaxValue.ToString();
            }
        }

        private void GStreamerStopToolStripMenuItem_Click(object sender, EventArgs e)
        {
            hudGStreamer.Stop();
        }

        private void HereLinkVideoToolStripMenuItem_Click(object sender, EventArgs e)
        {
            string ipaddr = "192.168.43.1";

            if (Settings.Instance["herelinkip"] != null)
                ipaddr = Settings.Instance["herelinkip"].ToString();

            InputBox.Show("herelink ip", "Enter herelink ip address", ref ipaddr);

            Settings.Instance["herelinkip"] = ipaddr;

            string url = String.Format(
                "rtspsrc location=rtsp://{0}:8554/fpv_stream latency=1 udp-reconnect=1 timeout=0 do-retransmission=false ! application/x-rtp ! rtph264depay ! h264parse ! queue ! avdec_h264 ! queue max-size-buffers=1 leaky=2 ! videoconvert ! video/x-raw,format=BGRx ! appsink name=outsink",
                ipaddr);

            GStreamer.GstLaunch = GStreamer.LookForGstreamer();

            if (!GStreamer.GstLaunchExists)
            {
                GStreamerUI.DownloadGStreamer();

                if (!GStreamer.GstLaunchExists)
                {
                    return;
                }
            }

            GCSViews.FlightData.hudGStreamer.Start(url);
        }

        private void hud_UserItem(object sender, EventArgs e)
        {
            Form selectform = new Form
            {
                Name = "select",
                Width = 50,
                Height = 50,
                Text = "Display This",
                AutoSize = true,
                StartPosition = FormStartPosition.CenterParent,
                MaximizeBox = false,
                MinimizeBox = false,
                AutoScroll = true

            };
            ThemeManager.ApplyThemeTo(selectform);

            object thisBoxed = MainV2.comPort.MAV.cs;
            Type test = thisBoxed.GetType();

            int max_length = 0;
            List<(string name, string desc)> fields = new List<(string, string)>();

            foreach (var field in test.GetProperties())
            {
                // field.Name has the field's name.
                object fieldValue = field.GetValue(thisBoxed, null); // Get value
                if (fieldValue == null)
                    continue;

                if (!fieldValue.IsNumber())
                    continue;

                if (field.Name.Contains("customfield"))
                {
                    if (CurrentState.custom_field_names.ContainsKey(field.Name))
                    {
                        string name = CurrentState.custom_field_names[field.Name];
                        max_length = Math.Max(max_length, TextRenderer.MeasureText(name, selectform.Font).Width);
                        fields.Add((field.Name, name));
                    }
                }
                else
                {
                    max_length = Math.Max(max_length, TextRenderer.MeasureText(field.Name, selectform.Font).Width);
                    fields.Add((field.Name, field.Name));
                }
            }

            max_length += 15;
            fields.Sort((a, b) => CurrentState.StringCompareTo(a.Item2, b.Item2));

            int col_count = (int) (Screen.FromControl(this).Bounds.Width * 0.8f) / max_length;
            int row_count = fields.Count / col_count + ((fields.Count % col_count == 0) ? 0 : 1);
            int row_height = 20;
            //selectform.MinimumSize = new Size(col_count * max_length, row_count * row_height);
            selectform.SuspendLayout();
            for (int i = 0; i < fields.Count; i++)
            {
                CheckBox chk_box = new CheckBox
                {
                    Text = fields[i].desc,
                    Name = fields[i].name,
                    Tag = "custom",
                    Location = new Point(5 + (i / row_count) * (max_length + 5), 2 + (i % row_count) * row_height),
                    Size = new Size(max_length, row_height),
                    Checked = hud1.CustomItems.ContainsKey(fields[i].name),
                    AutoSize = true
                };
                chk_box.CheckedChanged += chk_box_hud_UserItem_CheckedChanged;
                if (chk_box.Checked)
                    chk_box.BackColor = Color.Green;
                selectform.Controls.Add(chk_box);
            }

            selectform.ResumeLayout();
            selectform.Shown += (o, args) =>
            {
                selectform.Controls.ForEach(a =>
                {
                    if (a is CheckBox && ((CheckBox) a).Checked)
                        ((CheckBox) a).BackColor = Color.Green;
                });
            };

            selectform.ShowDialog(this);
        }

        private void hud1_DoubleClick(object sender, EventArgs e)
        {
            if (huddropout)
                return;

            if(hud1.Parent == SubMainLeft.Panel1)
                SubMainLeft.Panel1Collapsed = true;
            Form dropout = new Form();
            dropout.Text = "HUD Dropout";
            dropout.Size = new Size(hud1.Width, hud1.Height + 20);
            dropout.Tag = hud1.Parent;
            SubMainLeft.Panel1.Controls.Remove(hud1);
            dropout.Controls.Add(hud1);
            dropout.Resize += dropout_Resize;
            dropout.FormClosed += dropout_FormClosed;
            dropout.RestoreStartupLocation();
            dropout.Show();
            huddropout = true;
        }

        private void hud1_ekfclick(object sender, EventArgs e)
        {
            EKFStatus frm = new EKFStatus();
            frm.RestoreStartupLocation();
            frm.WindowState = FormWindowState.Normal;
            frm.FormClosed += (a, e2) => frm.SaveStartupLocation();
            frm.TopMost = true;
            frm.Show();
        }

        private void hud1_Resize(object sender, EventArgs e)
        {
            Console.WriteLine("HUD resize " + hud1.Width + " " + hud1.Height); // +"\n"+ System.Environment.StackTrace);

            if (hud1.Parent == this.SubMainLeft.Panel1)
            {
                var ht = SubMainLeft.SplitterDistance;
                if (ht >= hud1.Height + 5 || ht <= hud1.Height - 5)
                    SubMainLeft.SplitterDistance = hud1.Height;
            }
        }

        private void hud1_vibeclick(object sender, EventArgs e)
        {
            Vibration frm = new Vibration();
            frm.RestoreStartupLocation();
            frm.WindowState = FormWindowState.Normal;
            frm.FormClosed += (a, e2) => frm.SaveStartupLocation();
            frm.TopMost = true;
            frm.Show();
        }

        private void hud1_prearmclick(object sender, EventArgs e)
        {
            PrearmStatus frm = new PrearmStatus();
            frm.RestoreStartupLocation();
            frm.WindowState = FormWindowState.Normal;
            frm.FormClosed += (a, e2) => frm.SaveStartupLocation();
            frm.TopMost = true;
            frm.Show();
        }

        /// <summary>
        /// <para>Collapses or expands MainH.Panel1 depending on no. of controls within.</para>
        /// If you add controls to <b>SubMainLeft</b> that can be hidden, displaced or removed, add their first parent control here. <br/>
        /// Otherwise they'll prevent the collapsing of <b>SubMainLeft</b>.
        /// </summary>
        private void ManageLeftPanelVisibility()
        {
            // Define controls to check, ADD THEM HERE
            List<Control> controlsToCheck = new List<Control>()
            {
                SubMainLeft.Panel1, // contains hud1
                panel_persistent,   // might contain plugin controls
                tabControlactions   // contains the tabs
            };

            bool controlsEmpty = controlsToCheck.Sum(x => x.Controls.Count) == 0;
            bool panelVisible = !MainH.Panel1Collapsed;

            // if controls are empty, but panel is visible -> hide
            if (controlsEmpty && panelVisible)
                MainH.Panel1Collapsed = true;

            // if controls have content, but panel is hidden -> show
            if (!controlsEmpty && !panelVisible)
                MainH.Panel1Collapsed = false;
        }

        private void loadFileToolStripMenuItem_Click(object sender, EventArgs e)
        {
            POI.POILoad();
        }

        private void mainloop()
        {
            threadrun = true;
            EndPoint Remote = new IPEndPoint(IPAddress.Any, 0);

            DateTime tracklast = DateTime.Now.AddSeconds(0);

            DateTime tunning = DateTime.Now.AddSeconds(0);

            DateTime mapupdate = DateTime.Now.AddSeconds(0);

            DateTime vidrec = DateTime.Now.AddSeconds(0);

            DateTime waypoints = DateTime.Now.AddSeconds(0);

            DateTime updatescreen = DateTime.Now;

            DateTime transponderUpdate = DateTime.Now;

            DateTime tsreal = DateTime.Now;
            double taketime = 0;
            double timeerror = 0;

            while (!IsHandleCreated)
            {
                //await Task.Delay(1000);
                Thread.Sleep(1000);
            }

            while (threadrun)
            {
                if (MainV2.comPort.giveComport)
                {
                    //await Task.Delay(50);
                    Thread.Sleep(50);
                    updateBindingSource();
                    continue;
                }

                if (!MainV2.comPort.logreadmode)
                {
                    //await Task.Delay(50); // max is only ever 10 hz but we go a little faster to empty the serial queue
                    Thread.Sleep(50);
                }

                if (this.IsDisposed)
                {
                    threadrun = false;
                    break;
                }

                try
                {
                    if (aviwriter != null && vidrec.AddMilliseconds(1000 / 25.0) <= DateTime.Now)
                    {
                        vidrec = DateTime.Now;

                        hud1.streamjpgenable = true;

                        //aviwriter.avi_start("test.avi");
                        // add a frame
                        aviwriter.avi_add(hud1.streamjpg.GetBuffer(), (uint) hud1.streamjpg.Length);
                        // write header - so even partial files will play
                        aviwriter.avi_end(hud1.Width, hud1.Height, 25);
                    }
                }
                catch
                {
                    log.Error("Failed to write avi");
                }

                // log playback
                if (MainV2.comPort.logreadmode && MainV2.comPort.logplaybackfile != null)
                {
                    if (MainV2.comPort.BaseStream.IsOpen)
                    {
                        MainV2.comPort.logreadmode = false;
                        try
                        {
                            MainV2.comPort.logplaybackfile.Close();
                        }
                        catch
                        {
                            log.Error("Failed to close logfile");
                        }

                        MainV2.comPort.logplaybackfile = null;
                    }


                    //Console.WriteLine(DateTime.Now.Millisecond);

                    if (updatescreen.AddMilliseconds(300) < DateTime.Now)
                    {
                        try
                        {
                            updatePlayPauseButton(true);
                            updateLogPlayPosition();
                        }
                        catch
                        {
                            log.Error("Failed to update log playback pos");
                        }

                        updatescreen = DateTime.Now;
                    }

                    //Console.WriteLine(DateTime.Now.Millisecond + " done ");

                    DateTime logplayback = MainV2.comPort.lastlogread;
                    try
                    {
                        if (!MainV2.comPort.giveComport)
                        {
                            //await MainV2.comPort.readPacketAsync().ConfigureAwait(false);
                            MainV2.comPort.readPacketAsync().AwaitSync();
                        }
                    }
                    catch
                    {
                        log.Error("Failed to read log packet");
                    }

                    // time between packets
                    double act = (MainV2.comPort.lastlogread - logplayback).TotalMilliseconds;

                    if (act > 9999 || act < 0)
                        act = 0;

                    double ts = 0;
                    if (LogPlayBackSpeed == 0)
                        LogPlayBackSpeed = 0.01;
                    try
                    {
                        ts = Math.Min((act / LogPlayBackSpeed), 1000);
                    }
                    catch
                    {
                    }

                    if (LogPlayBackSpeed >= 4 && MainV2.speechEnable)
                        MainV2.speechEngine.SpeakAsyncCancelAll();

                    double timetook = (DateTime.Now - tsreal).TotalMilliseconds;
                    if (timetook != 0)
                    {
                        //Console.WriteLine("took: " + timetook + "=" + taketime + " " + (taketime - timetook) + " " + ts);
                        //Console.WriteLine(MainV2.comPort.lastlogread.Second + " " + DateTime.Now.Second + " " + (MainV2.comPort.lastlogread.Second - DateTime.Now.Second));
                        //if ((taketime - timetook) < 0)
                        {
                            timeerror += (taketime - timetook);
                            if (ts != 0)
                            {
                                ts += timeerror;
                                timeerror = 0;
                            }
                        }
                        if (Math.Abs(ts) > 1000)
                            ts = 1000;
                    }

                    taketime = ts;
                    tsreal = DateTime.Now;

                    if (ts > 0 && ts < 1000)
                        Thread.Sleep((int) ts);

                    // update currentstate of sysids on the port
                    foreach (var MAV in MainV2.comPort.MAVlist)
                    {
                        try
                        {
                            MAV.cs.UpdateCurrentSettings(null, false, MainV2.comPort, MAV);
                        }
                        catch (Exception ex)
                        {
                            log.Error(ex);
                        }
                    }

                    tracklast = tracklast.AddMilliseconds(ts - act);
                    tunning = tunning.AddMilliseconds(ts - act);

                    if (tracklast.Month != DateTime.Now.Month)
                    {
                        tracklast = DateTime.Now;
                        tunning = DateTime.Now;
                    }

                    try
                    {
                        if (MainV2.comPort.logplaybackfile != null &&
                            MainV2.comPort.logplaybackfile.BaseStream.Position ==
                            MainV2.comPort.logplaybackfile.BaseStream.Length)
                        {
                            MainV2.comPort.logreadmode = false;
                        }
                    }
                    catch
                    {
                        MainV2.comPort.logreadmode = false;
                    }
                }
                else
                {
                    // ensure we know to stop
                    if (MainV2.comPort.logreadmode)
                        MainV2.comPort.logreadmode = false;
                    updatePlayPauseButton(false);

                    if (!playingLog && MainV2.comPort.logplaybackfile != null)
                    {
                        continue;
                    }
                }

                try
                {
                    //CheckAndBindPreFlightData();
                    //Console.WriteLine(DateTime.Now.Millisecond);
                    //int fixme;
                    updateBindingSource();
                    // Console.WriteLine(DateTime.Now.Millisecond + " done ");

                    // battery warning.
                    // Use speech settings only if the following parameters are not set
                    // BATT_LOW_VOLT
                    // BATT_LOW_MAH
                    // BATT_CRT_VOLT
                    // BATT_CRT_MAH

                    double warnvolt = 0;
                    double warnpercent = 0;
                    double critvolt = 0;
                    double critpercent = 0;


                    if (MainV2.comPort.MAV.param.ContainsKey("BATT_LOW_VOLT")) warnvolt = MainV2.comPort.MAV.param["BATT_LOW_VOLT"].Value;
                    if (MainV2.comPort.MAV.param.ContainsKey("BATT_LOW_MAH") && MainV2.comPort.MAV.param.ContainsKey("BATT_CAPACITY"))
                    {
                        if (MainV2.comPort.MAV.param["BATT_LOW_MAH"].Value > 0)
                        {
                            warnpercent = MainV2.comPort.MAV.param["BATT_LOW_MAH"].Value / MainV2.comPort.MAV.param["BATT_CAPACITY"].Value * 100 ;
                        }
                    }

                    if (MainV2.comPort.MAV.param.ContainsKey("BATT_CRT_VOLT")) critvolt = MainV2.comPort.MAV.param["BATT_CRT_VOLT"].Value;
                    if (MainV2.comPort.MAV.param.ContainsKey("BATT_CRT_MAH") && MainV2.comPort.MAV.param.ContainsKey("BATT_CAPACITY"))
                    {
                        if (MainV2.comPort.MAV.param["BATT_CRT_MAH"].Value > 0)
                        {
                            critpercent = MainV2.comPort.MAV.param["BATT_CRT_MAH"].Value / MainV2.comPort.MAV.param["BATT_CAPACITY"].Value * 100 ;
                        }
                    }

                    if (warnvolt == 0)
                    {
                        warnvolt = Settings.Instance.GetDouble("speechbatteryvolt");
                    }
                    if (warnpercent == 0)
                    {
                        warnpercent = Settings.Instance.GetDouble("speechbatterypercent");
                    }

                    if (critvolt == 0) critvolt = warnvolt;
                    if (critpercent == 0) critpercent = warnpercent;

                    if (MainV2.comPort.MAV.cs.battery_voltage <= warnvolt)
                    {
                        hud1.lowvoltagealert = true;
                    }
                    else if ((MainV2.comPort.MAV.cs.battery_remaining) < warnpercent)
                    {
                        hud1.lowvoltagealert = true;
                    }
                    else
                    {
                        hud1.lowvoltagealert = false;
                    }

                    if (MainV2.comPort.MAV.cs.battery_voltage <= critvolt)
                    {
                        hud1.criticalvoltagealert = true;
                    }
                    else if ((MainV2.comPort.MAV.cs.battery_remaining) < critpercent)
                    {
                        hud1.criticalvoltagealert = true;
                    }
                    else
                    {
                        hud1.criticalvoltagealert = false;
                    }


                    // update opengltest
                    if (OpenGLtest.instance != null)
                    {
                        OpenGLtest.instance.rpy = new Vector3(MainV2.comPort.MAV.cs.roll,
                            MainV2.comPort.MAV.cs.pitch,
                            MainV2.comPort.MAV.cs.yaw);
                        OpenGLtest.instance.LocationCenter = new PointLatLngAlt(MainV2.comPort.MAV.cs.lat,
                            MainV2.comPort.MAV.cs.lng, MainV2.comPort.MAV.cs.altasl / CurrentState.multiplieralt,
                            "here");
                    }

                    // update opengltest2
                    if (OpenGLtest2.instance != null)
                    {
                        OpenGLtest2.instance.rpy = new Vector3(MainV2.comPort.MAV.cs.roll,
                            MainV2.comPort.MAV.cs.pitch,
                            MainV2.comPort.MAV.cs.yaw);
                        OpenGLtest2.instance.LocationCenter = new PointLatLngAlt(MainV2.comPort.MAV.cs.lat,
                            MainV2.comPort.MAV.cs.lng, MainV2.comPort.MAV.cs.altasl / CurrentState.multiplieralt,
                            "here");
                        OpenGLtest2.instance.Velocity = new Vector3(MainV2.comPort.MAV.cs.vx, MainV2.comPort.MAV.cs.vy,
                            MainV2.comPort.MAV.cs.vz);
                        OpenGLtest2.instance.WPs = MainV2.comPort.MAV.wps.Values.Select(a => (Locationwp) a).ToList();
                    }

                    // update vario info
                    Vario.SetValue(MainV2.comPort.MAV.cs.climbrate);

                    // udpate tunning tab
                    if (tunning.AddMilliseconds(75) < DateTime.Now && CB_tuning.Checked)
                    {
                        double time = (Environment.TickCount - tickStart) / 1000.0;
                        if (list1item != null)
                            list1.Add(time, (list1item.GetValue(MainV2.comPort.MAV.cs, null).ConvertToDouble()));
                        if (list2item != null)
                            list2.Add(time, (list2item.GetValue(MainV2.comPort.MAV.cs, null).ConvertToDouble()));
                        if (list3item != null)
                            list3.Add(time, (list3item.GetValue(MainV2.comPort.MAV.cs, null).ConvertToDouble()));
                        if (list4item != null)
                            list4.Add(time, (list4item.GetValue(MainV2.comPort.MAV.cs, null).ConvertToDouble()));
                        if (list5item != null)
                            list5.Add(time, (list5item.GetValue(MainV2.comPort.MAV.cs, null).ConvertToDouble()));
                        if (list6item != null)
                            list6.Add(time, (list6item.GetValue(MainV2.comPort.MAV.cs, null).ConvertToDouble()));
                        if (list7item != null)
                            list7.Add(time, (list7item.GetValue(MainV2.comPort.MAV.cs, null).ConvertToDouble()));
                        if (list8item != null)
                            list8.Add(time, (list8item.GetValue(MainV2.comPort.MAV.cs, null).ConvertToDouble()));
                        if (list9item != null)
                            list9.Add(time, (list9item.GetValue(MainV2.comPort.MAV.cs, null).ConvertToDouble()));
                        if (list10item != null)
                            list10.Add(time, (list10item.GetValue(MainV2.comPort.MAV.cs, null).ConvertToDouble()));
                        if (list11item != null)
                            list11.Add(time, (list11item.GetValue(MainV2.comPort.MAV.cs, null).ConvertToDouble()));
                        if (list12item != null)
                            list12.Add(time, (list12item.GetValue(MainV2.comPort.MAV.cs, null).ConvertToDouble()));
                        if (list13item != null)
                            list13.Add(time, (list13item.GetValue(MainV2.comPort.MAV.cs, null).ConvertToDouble()));
                        if (list14item != null)
                            list14.Add(time, (list14item.GetValue(MainV2.comPort.MAV.cs, null).ConvertToDouble()));
                        if (list15item != null)
                            list15.Add(time, (list15item.GetValue(MainV2.comPort.MAV.cs, null).ConvertToDouble()));
                        if (list16item != null)
                            list16.Add(time, (list16item.GetValue(MainV2.comPort.MAV.cs, null).ConvertToDouble()));
                        if (list17item != null)
                            list17.Add(time, (list17item.GetValue(MainV2.comPort.MAV.cs, null).ConvertToDouble()));
                        if (list18item != null)
                            list18.Add(time, (list18item.GetValue(MainV2.comPort.MAV.cs, null).ConvertToDouble()));
                        if (list19item != null)
                            list19.Add(time, (list19item.GetValue(MainV2.comPort.MAV.cs, null).ConvertToDouble()));
                        if (list20item != null)
                            list20.Add(time, (list20item.GetValue(MainV2.comPort.MAV.cs, null).ConvertToDouble()));
                    }

                    // update map - 0.3sec if connected , 2 sec if not connected
                    if (((MainV2.comPort.BaseStream.IsOpen || MainV2.comPort.logreadmode) &&
                         tracklast.AddSeconds(Settings.Instance.GetDouble("FD_MapUpdateDelay", 0.3)) < DateTime.Now) ||
                        tracklast.AddSeconds(2) < DateTime.Now)
                    {
                        // show disable joystick button
                        if (MainV2.joystick != null && MainV2.joystick.enabled)
                        {
                            this.BeginInvoke((MethodInvoker) delegate { but_disablejoystick.Visible = true; });
                        }

                        if (MainV2.comPort.MAV.cs.Location != PointLatLngAlt.Zero)
                        {
                            adsb.CurrentPosition = MainV2.comPort.MAV.cs.Location;
                        }
                        else
                        {
                            adsb.CurrentPosition = gMapControl1.Position;
                        }

                        // show proximity screen
                        if (MainV2.comPort.MAV?.Proximity != null && MainV2.comPort.MAV.Proximity.DataAvailable)
                        {
                            //this.BeginInvoke((MethodInvoker)delegate { new ProximityControl(MainV2.comPort.MAV).Show(); });
                        }

                        if (Settings.Instance.GetBoolean("CHK_maprotation"))
                        {
                            ////Check if we have more than one vehicle connected and disable CHK_maprotation if so
                            if (MainV2.comPort.MAVlist.Count > 1)
                            {
                                Settings.Instance["CHK_maprotation"] = "false";
                                //And set maprotation to zero
                                BeginInvoke((Action)delegate { gMapControl1.Bearing = 0; });
                            }
                            //gMapControl1.HoldInvalidation = true;
                            setMapBearing();

                        }

                        if (route == null)
                        {
                            route = new GMapRoute(trackPoints, "track");
                            routes.Routes.Add(route);
                        }

                        PointLatLng currentloc = new PointLatLng(MainV2.comPort.MAV.cs.lat, MainV2.comPort.MAV.cs.lng);

                        gMapControl1.HoldInvalidation = true;

                        int numTrackLength = Settings.Instance.GetInt32("NUM_tracklength", 200);
                        // maintain route history length
                        if (route.Points.Count > numTrackLength)
                        {
                            route.Points.RemoveRange(0,
                                route.Points.Count - numTrackLength);
                        }

                        // add new route point
                        if (MainV2.comPort.MAV.cs.lat != 0 && MainV2.comPort.MAV.cs.lng != 0)
                        {
                            route.Points.Add(currentloc);
                        }

                        if (!this.IsHandleCreated)
                            continue;

                        updateRoutePosition();

                        // update programed wp course
                        if (waypoints.AddSeconds(5) < DateTime.Now)
                        {
                            //Console.WriteLine("Doing FD WP's");
                            updateClearMissionRouteMarkers();

                            var wps = MainV2.comPort.MAV.wps.Values.ToList();
                            if (wps.Count >= 1)
                            {
                                var homeplla = new PointLatLngAlt(MainV2.comPort.MAV.cs.HomeLocation.Lat,
                                    MainV2.comPort.MAV.cs.HomeLocation.Lng,
                                    MainV2.comPort.MAV.cs.HomeLocation.Alt / CurrentState.multiplieralt, "H");

                                if (homeplla.Lat == 0 && homeplla.Lng == 0)
                                {
                                    homeplla = new PointLatLngAlt(MainV2.comPort.MAV.cs.PlannedHomeLocation.Lat,
                                        MainV2.comPort.MAV.cs.PlannedHomeLocation.Lng,
                                        MainV2.comPort.MAV.cs.PlannedHomeLocation.Alt / CurrentState.multiplieralt, "H");
                                }

                                var wpOverlay = new WPOverlay();

                                {
                                    List<Locationwp> mission_items;
                                    mission_items = MainV2.comPort.MAV.wps.Values.Select(a => (Locationwp) a).ToList();
                                    mission_items.RemoveAt(0);

                                    if (wps.Count == 1)
                                    {
                                        wpOverlay.CreateOverlay(homeplla,
                                            mission_items,
                                            0 / CurrentState.multiplieralt, 0 / CurrentState.multiplieralt,
                                            CurrentState.multiplieralt);
                                    }
                                    else
                                    {
                                        wpOverlay.CreateOverlay(homeplla,
                                            mission_items,
                                            0 / CurrentState.multiplieralt, 0 / CurrentState.multiplieralt,
                                            CurrentState.multiplieralt);

                                    }
                                }

                                var existing = gMapControl1.Overlays.Where(a => a.Id == wpOverlay.overlay.Id).ToList();
                                foreach (var b in existing)
                                {
                                    gMapControl1.Overlays.Remove(b);
                                }

                                gMapControl1.Overlays.Insert(1, wpOverlay.overlay);

                                wpOverlay.overlay.ForceUpdate();

                                try
                                {
                                    distanceBar1.ClearWPDist();

                                    var i = -1;
                                    var travdist = 0.0;
                                    if (wpOverlay.pointlist.Count > 0)
                                    {
                                        var lastplla = wpOverlay.pointlist.Where(a => a != null).FirstOrDefault();
                                        foreach (var plla in wpOverlay.pointlist)
                                        {
                                            i++;
                                            if (plla == null)
                                                continue;

                                            var dist = lastplla.GetDistance(plla);

                                            distanceBar1.AddWPDist((float) dist);

                                            if (i <= MainV2.comPort.MAV.cs.wpno)
                                            {
                                                travdist += dist;
                                            }
                                        }
                                    }

                                    travdist -= MainV2.comPort.MAV.cs.wp_dist;

                                    if (MainV2.comPort.MAV.cs.mode.ToUpper() == "AUTO")
                                        distanceBar1.traveleddist = (float) travdist;

                                }
                                catch (Exception ex)
                                {
                                    log.Error(ex);
                                }
                            }

                            RegeneratePolygon();

                            // update rally points

                            rallypointoverlay.Markers.Clear();

                            foreach (var mark in MainV2.comPort.MAV.rallypoints.Values)
                            {
                                rallypointoverlay.Markers.Add(new GMapMarkerRallyPt(new PointLatLngAlt(mark), CurrentState.multiplieralt));
                            }

                            geofence.Clear();

                            var fenceoverlay = new WPOverlay();
                            fenceoverlay.overlay.Id = "fence";

                            fenceoverlay.CreateOverlay(PointLatLngAlt.Zero,
                                MainV2.comPort.MAV.fencepoints.Values.Select(a => (Locationwp) a).ToList(), 0, 0,
                                CurrentState.multiplieralt);

                            var fence = mymap.Overlays.Where(a => a.Id == "fence");
                            if (fence.Count() > 0)
                                mymap.Overlays.Remove(fence.First());
                            mymap.Overlays.Add(fenceoverlay.overlay);

                            fenceoverlay.overlay.ForceUpdate();

                            // optional on Flight data
                            if (MainV2.ShowAirports)
                            {
                                // airports
                                foreach (var item in Airports.getAirports(gMapControl1.Position).ToArray())
                                {
                                    try
                                    {
                                        rallypointoverlay.Markers.Add(new GMapMarkerAirport(item)
                                        {
                                            ToolTipText = item.Tag,
                                            ToolTipMode = MarkerTooltipMode.OnMouseOver
                                        });
                                    }
                                    catch (Exception e)
                                    {
                                        log.Error(e);
                                    }
                                }
                            }

                            //nofly
                            NoFly.NoFly.UpdateNoFlyZone(this, gMapControl1.Position);

                            waypoints = DateTime.Now;
                        }

                        //updateClearRoutesMarkers();

                        // add this after the mav icons are drawn
                        if (MainV2.comPort.MAV.cs.Base != null &&
                            MainV2.comPort.MAV.cs.Base != PointLatLngAlt.Zero)
                        {
                            addMissionRouteMarker(new GMarkerGoogle(currentloc, GMarkerGoogleType.blue_dot)
                            {
                                Position = MainV2.comPort.MAV.cs.Base,
                                ToolTipText = "Base",
                                ToolTipMode = MarkerTooltipMode.OnMouseOver
                            });
                        }

                        // add gimbal point center

                        try
                        {
                            if (MainV2.comPort.MAV.param.ContainsKey("MNT_STAB_TILT")
                                && MainV2.comPort.MAV.param.ContainsKey("MNT_STAB_ROLL")
                                && MainV2.comPort.MAV.param.ContainsKey("MNT_TYPE"))
                            {
                                float temp1 = (float) MainV2.comPort.MAV.param["MNT_STAB_TILT"];
                                float temp2 = (float) MainV2.comPort.MAV.param["MNT_STAB_ROLL"];

                                float temp3 = (float) MainV2.comPort.MAV.param["MNT_TYPE"];

                                if (MainV2.comPort.MAV.param.ContainsKey("MNT_STAB_PAN") &&
                                    // (float)MainV2.comPort.MAV.param["MNT_STAB_PAN"] == 1 &&
                                    ((float) MainV2.comPort.MAV.param["MNT_STAB_TILT"] == 1 &&
                                     (float) MainV2.comPort.MAV.param["MNT_STAB_ROLL"] == 0) ||
                                    (float) MainV2.comPort.MAV.param["MNT_TYPE"] == 4) // storm driver
                                {
                                    var marker = GimbalPoint.ProjectPoint(MainV2.comPort);

                                    if (marker != PointLatLngAlt.Zero)
                                    {
                                        MainV2.comPort.MAV.cs.GimbalPoint = marker;

                                        addMissionRouteMarker(new GMarkerGoogle(marker, GMarkerGoogleType.blue_dot)
                                        {
                                            ToolTipText = "Camera Target\n" + marker,
                                            ToolTipMode = MarkerTooltipMode.OnMouseOver
                                        });
                                    }
                                }
                            }
                        }
                        catch (Exception ex)
                        {
                            log.Error(ex);
                        }

                        try
                        {

                            // cleanup old - no markers where added, so remove all old
                            if (MainV2.comPort.MAV.camerapoints.Count < photosoverlay.Markers.Count)
                                photosoverlay.Markers.Clear();

                            var min_interval = 0.0;
                            if (MainV2.comPort.MAV.param.ContainsKey("CAM_MIN_INTERVAL"))
                                min_interval = MainV2.comPort.MAV.param["CAM_MIN_INTERVAL"].Value / 1000.0;

                            // set fov's based on last grid calc
                            if (Settings.Instance["camera_fovh"] != null)
                            {
                                GMapMarkerPhoto.hfov = Settings.Instance.GetDouble("camera_fovh");
                                GMapMarkerPhoto.vfov = Settings.Instance.GetDouble("camera_fovv");
                            }

                            // add new - populate camera_feedback to map
                            double oldtime = double.MinValue;
                            foreach (var mark in MainV2.comPort.MAV.camerapoints.ToArray())
                            {
                                var timesincelastshot = (mark.time_usec / 1000.0) / 1000.0 - oldtime;
                                MainV2.comPort.MAV.cs.timesincelastshot = timesincelastshot;
                                bool contains = photosoverlay.Markers.Any(p => p.Tag.Equals(mark.time_usec));
                                if (!contains)
                                {
                                    if (timesincelastshot < min_interval)
                                        addMissionPhotoMarker(new GMapMarkerPhoto(mark, true));
                                    else
                                        addMissionPhotoMarker(new GMapMarkerPhoto(mark, false));
                                }

                                oldtime = (mark.time_usec / 1000.0) / 1000.0;
                            }

                            var GMapMarkerOverlapCount = new GMapMarkerOverlapCount(PointLatLng.Empty);

                            // age current
                            int camcount = MainV2.comPort.MAV.camerapoints.Count;
                            int a = 0;
                            foreach (var mark in photosoverlay.Markers)
                            {
                                if (mark is GMapMarkerPhoto)
                                {
                                    if (CameraOverlap)
                                    {
                                        var marker = ((GMapMarkerPhoto) mark);
                                        // abandon roll higher than 25 degrees
                                        if (Math.Abs(marker.Roll) < 25)
                                        {
                                            GMapMarkerOverlapCount.Add(
                                                ((GMapMarkerPhoto) mark).footprintpoly);
                                        }
                                    }

                                    if (a < (camcount - 4))
                                        ((GMapMarkerPhoto) mark).drawfootprint = false;
                                    else
                                        ((GMapMarkerPhoto) mark).drawfootprint = true;
                                }

                                a++;
                            }

                            if (CameraOverlap)
                            {
                                if (!kmlpolygons.Markers.Contains(GMapMarkerOverlapCount) &&
                                    camcount > 0)
                                {
                                    kmlpolygons.Markers.Clear();
                                    kmlpolygons.Markers.Add(GMapMarkerOverlapCount);
                                }
                            }
                            else if (kmlpolygons.Markers.Contains(GMapMarkerOverlapCount))
                            {
                                kmlpolygons.Markers.OfType<GMapMarkerOverlapCount>().ToArray()
                                    .ForEach(c => kmlpolygons.Markers.Remove(c));
                            }
                        }
                        catch (Exception ex)
                        {
                            log.Error(ex);
                        }

                        // draw AIS
                        updateMarkersAsNeeded<MAVLink.mavlink_ais_vessel_t, GMapMarkerAISBoat>(AIS.Vessels, adsbais,
                            (item) => { return item.MMSI.ToString(); },
                            (marker) => { return ((MAVLink.mavlink_ais_vessel_t) marker.Tag).MMSI.ToString(); },
                            (item) =>
                            {
                                return new GMapMarkerAISBoat(new PointLatLngAlt(item.lat / 1e7, item.lon / 1e7, 0),
                                    item.heading / 100.0f)
                                {
                                    Tag = item
                                };
                            }, (item, markerin) =>
                            {
                                var marker = markerin as GMapMarkerAISBoat;
                                marker.Position = new PointLatLngAlt(item.lat / 1e7, item.lon / 1e7, 0);
                                marker.heading = item.heading / 100.0f;
                                marker.ToolTipText = "MMSI: " + item.MMSI + "\n" +
                                                     "Speed: " + (item.velocity / 100).ToString("0 m/s") + "\n" +
                                                     "TurnRate: " + (item.turn_rate / 100).ToString("0");
                                marker.ToolTipMode = MarkerTooltipMode.OnMouseOver;
                                marker.Tag = item;
                            });

                        lock (MainV2.instance.adsblock)
                        {
                            // draw OA_DB
                            foreach (adsb.PointLatLngAltHdg plla in MainV2.instance.adsbPlanes.Values)
                            {
                                if (plla.Raw != null)
                                {
                                    var msg = ((MAVLink.mavlink_adsb_vehicle_t) plla.Raw);
                                    if (msg.emitter_type == 255 &&
                                        Encoding.ASCII.GetString(msg.callsign).Trim('\0') == "OA_DB")
                                    {
                                        // cm
                                        var radius = msg.squawk;

                                        if (((DateTime) plla.Time) > DateTime.Now.AddSeconds(-10))
                                            addMissionRouteMarker(new GMapMarkerDistance(plla, radius / 100.0, 0)
                                                {Pen = new Pen(Color.Red, 3)});
                                        continue;
                                    }
                                }
                            }

                            // filter out OA_DB adsb
                            var adsbitems = MainV2.instance.adsbPlanes.Values.Where(a =>
                            {
                                if (a.Raw != null)
                                {
                                    var msg = ((MAVLink.mavlink_adsb_vehicle_t) a.Raw);
                                    if (msg.emitter_type == 255 &&
                                        Encoding.ASCII.GetString(msg.callsign).Trim('\0') == "OA_DB")
                                    {
                                        return false;
                                    }
                                }

                                return true;
                            });

                            //draw ADSB
                            updateMarkersAsNeeded<adsb.PointLatLngAltHdg, GMapMarkerADSBPlane>(adsbitems, adsbais,
                                (plla) => { return plla.Tag; },
                                (marker) => { return ((adsb.PointLatLngAltHdg) marker?.Tag)?.Tag; },
                                (pllac) =>
                                {
                                    return new GMapMarkerADSBPlane(pllac, pllac.Heading)
                                    {
                                        Tag = pllac
                                    };
                                },
                                (pllau, marker) =>
                                {
                                    var adsbplane = marker as GMapMarkerADSBPlane;

                                    if (adsbplane == null || pllau == null)
                                        return;

                                    adsbplane.ToolTipText = "ICAO: " + pllau.Tag + "\n" +
                                                            "Callsign: " + pllau.CallSign + "\n" +
                                                            "Squawk: " + pllau.Squawk.ToString("X4") + "\n" +
                                                            "Alt: " + (pllau.Alt * CurrentState.multiplieralt).ToString("0") + " " + CurrentState.AltUnit + "\n" +
                                                            "Speed: " + (pllau.Speed / 100 /* cm to m */ * CurrentState.multiplierspeed).ToString("0") + " " + CurrentState.SpeedUnit + "\n" +
                                                            "VSpeed: " + (pllau.VerticalSpeed / 100 /* cm to m */ * CurrentState.multiplierspeed).ToString("F1") + " " + CurrentState.SpeedUnit + "\n" +
                                                            "Heading: " + pllau.Heading.ToString("0") + "°";
                                    // Add distance
                                    if (MainV2.comPort.MAV.cs.Location.Lat != 0 && MainV2.comPort.MAV.cs.Location.Lng != 0)
                                        adsbplane.ToolTipText += "\n" + "Distance: " + (pllau.GetDistance(MainV2.comPort.MAV.cs.Location) * CurrentState.multiplierdist).ToString("0") + " " + CurrentState.DistanceUnit;
                                    // Add collision threat level
                                    if (pllau.ThreatLevel != MAVLink.MAV_COLLISION_THREAT_LEVEL.NONE)
                                        adsbplane.ToolTipText += "\n" + "Collision risk: " + (pllau.ThreatLevel == MAVLink.MAV_COLLISION_THREAT_LEVEL.LOW ? "Warning" : "Danger");
                                    adsbplane.ToolTipMode = MarkerTooltipMode.OnMouseOver;
                                    adsbplane.Position = pllau;
                                    adsbplane.heading = pllau.Heading;
                                    adsbplane.Tag = pllau;

                                    if (((DateTime) pllau.Time) > DateTime.Now.AddSeconds(-30))
                                    {
                                        adsbplane.IsVisible = true;

                                        switch (pllau.ThreatLevel)
                                        {
                                            case MAVLink.MAV_COLLISION_THREAT_LEVEL.NONE:
                                                adsbplane.AlertLevel = GMapMarkerADSBPlane.AlertLevelOptions.Orange;
                                                break;
                                            case MAVLink.MAV_COLLISION_THREAT_LEVEL.LOW:
                                                adsbplane.AlertLevel = GMapMarkerADSBPlane.AlertLevelOptions.Orange;
                                                break;
                                            case MAVLink.MAV_COLLISION_THREAT_LEVEL.HIGH:
                                                adsbplane.AlertLevel = GMapMarkerADSBPlane.AlertLevelOptions.Red;
                                                break;
                                        }
                                    }
                                    else
                                    {
                                        adsbplane.IsVisible = false;
                                    }
                                });
                        }


                        if (route.Points.Count > 0)
                        {
                            // add primary route icon

                            // draw guide mode point for only main mav
                            if (MainV2.comPort.MAV.cs.mode.ToLower() == "guided" &&
                                MainV2.comPort.MAV.GuidedMode.x != 0)
                            {
                                FlightPlanner.addpolygonmarker(this, "Guided Mode", MainV2.comPort.MAV.GuidedMode.y / 1e7,
                                    MainV2.comPort.MAV.GuidedMode.x / 1e7, (int) MainV2.comPort.MAV.GuidedMode.z,
                                    Color.Blue,
                                    routes);
                            }

                            // draw all icons for all connected mavs
                            foreach (var port in MainV2.Comports.ToArray())
                            {
                                // draw the mavs seen on this port
                                foreach (var MAV in port.MAVlist)
                                {
                                    if (MAV == MainV2.comPort?.MAV)
                                    {
                                        // We will draw this last
                                        continue;
                                    }
                                    addMAVMarker(MAV);
                                }
                            }

                            // Draw the active aircraft
                            addMAVMarker(MainV2.comPort.MAV);

                            if (route.Points.Count == 0 || route.Points[route.Points.Count - 1].Lat != 0 &&
                                (mapupdate.AddSeconds(3) < DateTime.Now) && CHK_autopan.Checked)
                            {
                                updateMapPosition(currentloc);
                                mapupdate = DateTime.Now;
                            }

                            if (route.Points.Count == 1 && gMapControl1.Zoom == 3) // 3 is the default load zoom
                            {
                                updateMapPosition(currentloc);
                                updateMapZoom(17);
                            }
                        }

                        prop.Update(MainV2.comPort.MAV.cs.HomeLocation, MainV2.comPort.MAV.cs.Location,
                            MainV2.comPort.MAV.cs.battery_kmleft);

                        prop.alt = MainV2.comPort.MAV.cs.alt;
                        prop.altasl = MainV2.comPort.MAV.cs.altasl;
                        prop.center = gMapControl1.Position;

                        // Update camera bounds
                        cameraBounds.Polygons.Clear();
                        if (MainV2.comPort?.MAV?.Camera != null)
                        {
                            var cam = MainV2.comPort.MAV.Camera;
                            var p1 = cam?.CalculateImagePointLocation(-1, -1);
                            var p2 = cam?.CalculateImagePointLocation(-1, 1);
                            var p3 = cam?.CalculateImagePointLocation(1, 1);
                            var p4 = cam?.CalculateImagePointLocation(1, -1);

                            if(p1 != null && p2 != null && p3 != null && p4 != null)
                            {
                                cameraBounds.Polygons.Add(
                                    new GMap.NET.WindowsForms.GMapPolygon(
                                        new List<GMap.NET.PointLatLng>
                                        {
                                            new GMap.NET.PointLatLng(p1.Lat, p1.Lng),
                                            new GMap.NET.PointLatLng(p2.Lat, p2.Lng),
                                            new GMap.NET.PointLatLng(p3.Lat, p3.Lng),
                                            new GMap.NET.PointLatLng(p4.Lat, p4.Lng)
                                        },
                                        "CameraBounds"
                                    )
                                    {
                                        Fill = Brushes.Transparent,
                                        Stroke = new Pen(Color.DarkBlue, 3)
                                    }
                                );
                            }
                        }

                        gMapControl1.HoldInvalidation = false;

                        if (gMapControl1.Visible)
                        {
                            this.BeginInvokeIfRequired(()=>
                            {
                                gMapControl1.Invalidate();
                            });
                        }

                        tracklast = DateTime.Now;
                    }
                }
                catch (Exception ex)
                {
                    log.Error(ex);
                    Tracking.AddException(ex);
                    Console.WriteLine("FD Main loop exception " + ex);
                }

                if (MainV2.comPort.MAV.cs.xpdr_status_pending || transponderUpdate.AddMilliseconds(5000) < DateTime.Now)
                {
                    BeginInvoke((Action) updateTransponder);
                    transponderUpdate = DateTime.Now;
                }
            }

            Console.WriteLine("FD Main loop exit");
        }


        public void updateMarkersAsNeeded<TBuilder, TMarker>(IEnumerable<TBuilder> list, GMapOverlay gMapOverlay,
            Func<TBuilder, string> GetTagSource, Func<GMapMarker, string> GetTagMarker,
            Func<TBuilder, GMapMarker> create, Action<TBuilder, GMapMarker> update)
        {
            if (list == null || gMapOverlay == null || GetTagSource == null
                || GetTagMarker == null || create == null || update == null)
                return;

            var markers = gMapOverlay.Markers.Where(a => a is TMarker).ToArray();

            foreach (var item in list)
            {
                if (item == null)
                    continue;

                if (markers.Any(a => a is TMarker && GetTagMarker(a) == GetTagSource(item)))
                {
                    update(item, markers.First(a => a is TMarker && GetTagMarker(a) == GetTagSource(item)));
                }
                else
                {
                    // skip invalid tags
                    if (GetTagSource(item) == null)
                        continue;
                    // new marker
                    var marker = create(item);
                    if (marker == null)
                        continue;
                    update(item, marker);
                    BeginInvoke((Action) delegate { gMapOverlay.Markers.Add(marker); });
                }
            }

            // run cleanup
            var sourcelist = list.Select(item => GetTagSource(item));
            markers.ForEach(a =>
            {
                if (a is TMarker && !sourcelist.Contains(GetTagMarker(a)))
                    BeginInvoke((Action) delegate { gMapOverlay.Markers.Remove(a); });
            });
            // remove dups - can happen because the delayed invoke on first create
            sourcelist.Distinct().ForEach(a =>
            {
                var sublist = markers.Where(b => b.Tag != null && GetTagMarker(b) == a);
                if (sublist.Count() > 1)
                    BeginInvoke((Action) delegate { gMapOverlay.Markers.Remove(sublist.Last()); });
            });
        }

        private void Messagetabtimer_Tick(object sender, EventArgs e)
        {
            var messagetime = MainV2.comPort.MAV.cs.messages.LastOrDefault().time;
            if (messagecount != messagetime.toUnixTime())
            {
                try
                {
                    StringBuilder message = new StringBuilder();
                    MainV2.comPort.MAV.cs.messages.ForEach(x =>
                    {
                        message.Insert(0, x.Item1 + " : " + x.Item2 + "\r\n");
                    });
                    txt_messagebox.Text = message.ToString();

                    messagecount = messagetime.toUnixTime();
                }
                catch (Exception ex)
                {
                    log.Error(ex);
                }
            }

            coords1.AltUnit = CurrentState.AltUnit;
        }

        private void modifyandSetAlt_Click(object sender, EventArgs e)
        {
            int newalt = (int) modifyandSetAlt.Value;
            try
            {
                MainV2.comPort.setNewWPAlt(new Locationwp {alt = newalt / CurrentState.multiplieralt});
            }
            catch
            {
                CustomMessageBox.Show(Strings.ErrorCommunicating, Strings.ERROR);
            }
        }

        private void modifyandSetLoiterRad_Click(object sender, EventArgs e)
        {
            int newrad = (int) modifyandSetLoiterRad.Value;

            try
            {
                MainV2.comPort.setParam(new[] {"LOITER_RAD", "WP_LOITER_RAD"}, newrad / CurrentState.multiplierdist);
            }
            catch
            {
                CustomMessageBox.Show(Strings.ErrorCommunicating, Strings.ERROR);
            }
        }

        private async void modifyandSetSpeed_Click(object sender, EventArgs e)
        {
            try
            {
                await MainV2.comPort.doCommandAsync(MainV2.comPort.MAV.sysid, MainV2.comPort.MAV.compid,
                        MAVLink.MAV_CMD.DO_CHANGE_SPEED, 0, (float) modifyandSetSpeed.Value, 0, 0, 0, 0, 0)
                    .ConfigureAwait(true);
            }
            catch
            {
                CustomMessageBox.Show(Strings.ErrorCommunicating, Strings.ERROR);
            }
        }

        private void modifyandSetSpeed_ParentChanged(object sender, EventArgs e)
        {
        }

        void mymap_Paint(object sender, PaintEventArgs e)
        {
            distanceBar1.DoPaintRemote(e);
        }

        void NoFly_NoFlyEvent(object sender, NoFly.NoFly.NoFlyEventArgs e)
        {
            BeginInvoke((Action) delegate
            {
                gMapControl1.Overlays.Add(e.NoFlyZones);
            });
        }

        private void onOffCameraOverlapToolStripMenuItem_Click(object sender, EventArgs e)
        {
            CameraOverlap = onOffCameraOverlapToolStripMenuItem.Checked;

            foreach (var mark in photosoverlay.Markers.ToArray())
            {
                if (mark is GMapMarkerPhoto)
                {
                    if (!CameraOverlap)
                    {
                        photosoverlay.Markers.Remove(mark);
                    }
                }
            }
        }

        void POI_POIModified(object sender, EventArgs e)
        {
            POI.UpdateOverlay(poioverlay);
        }

        private void PointCameraCoordsToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            var location = "";
            InputBox.Show("Enter Coords", "Please enter the coords 'lat;long;alt(abs)' or 'lat;long'", ref location);

            var split = location.Split(';');

            if (split.Length == 3)
            {
                var lat = float.Parse(split[0], CultureInfo.InvariantCulture);
                var lng = float.Parse(split[1], CultureInfo.InvariantCulture);
                var alt = float.Parse(split[2], CultureInfo.InvariantCulture);

                MainV2.comPort.doCommandInt((byte) MainV2.comPort.sysidcurrent, (byte) MainV2.comPort.compidcurrent,
                    MAVLink.MAV_CMD.DO_SET_ROI, 0, 0, 0, 0, (int) (lat * 1e7),
                    (int) (lng * 1e7),  ((alt / CurrentState.multiplieralt) ));
            }
            else if (split.Length == 2)
            {
                var lat = float.Parse(split[0], CultureInfo.InvariantCulture);
                var lng = float.Parse(split[1], CultureInfo.InvariantCulture);
                var alt = (float)srtm.getAltitude(lat, lng).alt;

                MainV2.comPort.doCommandInt((byte) MainV2.comPort.sysidcurrent, (byte) MainV2.comPort.compidcurrent,
                    MAVLink.MAV_CMD.DO_SET_ROI, 0, 0, 0, 0, (int) (lat * 1e7),
                    (int) (lng * 1e7),  ((alt)));
            }
            else
            {
                CustomMessageBox.Show(Strings.InvalidField, Strings.ERROR);
            }
        }

        private void pointCameraHereToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (!MainV2.comPort.BaseStream.IsOpen)
            {
                CustomMessageBox.Show("Please Connect First");
                return;
            }

            string alt = "0";
            if (DialogResult.Cancel == InputBox.Show("Enter Alt",
                "Enter Target Alt (Relative to home)", ref alt))
                return;

            if (!float.TryParse(alt, out var intalt))
            {
                CustomMessageBox.Show("Bad Alt");
                return;
            }

            if (MouseDownStart.Lat == 0.0 || MouseDownStart.Lng == 0.0)
            {
                CustomMessageBox.Show("Bad Lat/Long");
                return;
            }

            try
            {
                MainV2.comPort.doCommandInt((byte) MainV2.comPort.sysidcurrent, (byte) MainV2.comPort.compidcurrent,
                    MAVLink.MAV_CMD.DO_SET_ROI, 0, 0, 0, 0, (int) (MouseDownStart.Lat * 1e7),
                    (int) (MouseDownStart.Lng * 1e7),  ((intalt / CurrentState.multiplieralt)),
                    frame: MAVLink.MAV_FRAME.GLOBAL_RELATIVE_ALT);
            }
            catch
            {
                CustomMessageBox.Show(Strings.CommandFailed, Strings.ERROR);
            }
        }

        private void quickView_DoubleClick(object sender, EventArgs e)
        {
            if (MainV2.DisplayConfiguration.lockQuickView)
                return;

            QuickView qv = (QuickView) sender;

            Form selectform = new Form
            {
                Name = "select",
                Width = MainV2.instance.Width - 100,
                Height = MainV2.instance.Height - 100,
                Text = "Display This",
                AutoSize = false,
                StartPosition = FormStartPosition.CenterParent,
                MaximizeBox = false,
                MinimizeBox = false,
                AutoScroll = true,
                FormBorderStyle = FormBorderStyle.FixedDialog

            };
            ThemeManager.ApplyThemeTo(selectform);

            object thisBoxed = MainV2.comPort.MAV.cs;
            Type test = thisBoxed.GetType();

            int max_length = 0;
            List<(string name, string desc)> fields = new List<(string, string)>();

            foreach (var field in test.GetProperties())
            {
                // field.Name has the field's name.
                object fieldValue = field.GetValue(thisBoxed, null); // Get value
                if (fieldValue == null)
                    continue;

                if (!fieldValue.IsNumber())
                {
                    if(fieldValue is bool)
                    {
                        fieldValue = ((bool)fieldValue) == true ? 1 : 0;
                    }
                    else
                        continue;
                }

                if (field.Name.Contains("customfield"))
                {
                    if (CurrentState.custom_field_names.ContainsKey(field.Name))
                    {
                        string name = CurrentState.custom_field_names[field.Name];
                        max_length = Math.Max(max_length, TextRenderer.MeasureText(name, selectform.Font).Width);
                        fields.Add((field.Name, name));
                    }
                }
                else
                {
                    var fieldDesc = MainV2.comPort.MAV.cs.GetFieldDesc(field.Name);
                    max_length = Math.Max(max_length, TextRenderer.MeasureText(fieldDesc, selectform.Font).Width);
                    fields.Add((field.Name, fieldDesc));
                }
            }

            max_length += 25;
            fields.Sort((a, b) => a.Item2.CompareTo(b.Item2));

            int col_count = (int) (Screen.FromControl(this).Bounds.Width * 0.8f) / max_length;
            int row_count = fields.Count / col_count + ((fields.Count % col_count == 0) ? 0 : 1);
            int row_height = 20;
            //selectform.MinimumSize = new Size(col_count * max_length, row_count * row_height);
            selectform.SuspendLayout();
            for (int i = 0; i < fields.Count; i++)
            {
                CheckBox chk_box = new CheckBox
                {
                    // dont change to ToString() = null exception
                    Checked = qv.Tag != null && qv.Tag.ToString() == fields[i].name,
                    Text = fields[i].desc,
                    Name = fields[i].name,
                    Tag = qv,
                    Location = new Point(5 + (i / row_count) * (max_length + 5), 2 + (i % row_count) * row_height),
                    Size = new Size(max_length, row_height),
                    AutoSize = true
                };
                chk_box.CheckedChanged += chk_box_quickview_CheckedChanged;
                if (chk_box.Checked)
                    chk_box.BackColor = Color.Green;
                selectform.Controls.Add(chk_box);
            }

            selectform.ResumeLayout();

            selectform.Shown += (o, args) =>
            {
                selectform.Controls.ForEach(a =>
                {
                    if (a is CheckBox && ((CheckBox) a).Checked)
                        ((CheckBox) a).BackColor = Color.Green;
                });
            };

            selectform.ShowDialog(this);
        }

        private void recordHudToAVIToolStripMenuItem_Click(object sender, EventArgs e)
        {
            stopRecordToolStripMenuItem_Click(sender, e);

            CustomMessageBox.Show("Output avi will be saved to the log folder");

            aviwriter = new AviWriter();
            try
            {
                Directory.CreateDirectory(Settings.Instance.LogDir);
                aviwriter.avi_start(Settings.Instance.LogDir + Path.DirectorySeparatorChar +
                                    DateTime.Now.ToString("yyyy-MM-dd HH-mm-ss") + ".avi");

                recordHudToAVIToolStripMenuItem.Text = "Recording";
            }
            catch (UnauthorizedAccessException ex)
            {
                CustomMessageBox.Show(ex.Message, Strings.ERROR);
            }
        }

        /// <summary>
        /// used to redraw the polygon
        /// </summary>
        void RegeneratePolygon()
        {
            List<PointLatLng> polygonPoints = new List<PointLatLng>();

            if (routes == null)
                return;

            foreach (GMapMarker m in polygons.Markers)
            {
                if (m is GMapMarkerRect)
                {
                    m.Tag = polygonPoints.Count;
                    polygonPoints.Add(m.Position);
                }
            }

            if (polygonPoints.Count < 2)
                return;

            GMapRoute homeroute = new GMapRoute("homepath");
            homeroute.Stroke = new Pen(Color.Yellow, 2);
            homeroute.Stroke.DashStyle = DashStyle.Dash;
            // add first point past home
            homeroute.Points.Add(polygonPoints[1]);
            // add home location
            homeroute.Points.Add(polygonPoints[0]);
            // add last point
            homeroute.Points.Add(polygonPoints[polygonPoints.Count - 1]);

            GMapRoute wppath = new GMapRoute("wp path");
            wppath.Stroke = new Pen(Color.Yellow, 4);
            wppath.Stroke.DashStyle = DashStyle.Custom;

            for (int a = 1; a < polygonPoints.Count; a++)
            {
                wppath.Points.Add(polygonPoints[a]);
            }

            BeginInvoke((Action) delegate
            {
                polygons.Routes.Add(homeroute);
                polygons.Routes.Add(wppath);
            });
        }

        private void resetToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Refresh();
        }

        void run_selected_script()
        {
            script = new Script(checkBoxRedirectOutput.Checked);
            scriptstarted.Release();
            script.runScript(selectedscript);
            scriptrunning = false;
        }

        private void russianHudToolStripMenuItem_Click(object sender, EventArgs e)
        {
            hud1.Russian = !hud1.Russian;
            Settings.Instance["russian_hud"] = hud1.Russian.ToString();
        }

        private void saveFileToolStripMenuItem_Click(object sender, EventArgs e)
        {
            POI.POISave();
        }

        public void saveTabControlActions()
        {
            string answer = "";

            foreach (TabPage tabPage in tabControlactions.TabPages)
            {
                answer += tabPage.Name + ";";
            }

            Settings.Instance["tabcontrolactions"] = answer;
        }

        private void scriptChecker_Tick(object sender, EventArgs e)
        {
            if (!scriptrunning)
            {
                labelScriptStatus.Text = "Script Status: Finished (or aborted)";
                scriptChecker.Enabled = false;
                BUT_select_script.Enabled = true;
                BUT_run_script.Enabled = true;
                BUT_abort_script.Visible = false;
                BUT_edit_selected.Enabled = true;
                checkBoxRedirectOutput.Enabled = true;
            }
            else if ((script != null) && (checkBoxRedirectOutput.Checked) && (!outputwindowstarted))
            {
                outputwindowstarted = true;

                ScriptConsole console = new ScriptConsole();
                console.SetScript(script);
                ThemeManager.ApplyThemeTo(console);
                console.Show();
                console.BringToFront();
                components.Add(console);
            }
        }

        private void setAspectRatioToolStripMenuItem_Click(object sender, EventArgs e)
        {
            hud1.SixteenXNine = !hud1.SixteenXNine;
            hud1.doResize();
        }

        private void setEKFHomeHereToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (!MainV2.comPort.BaseStream.IsOpen)
                return;

            var alt = srtm.getAltitude(MouseDownStart.Lat, MouseDownStart.Lng);

            if (alt.currenttype != srtm.tiletype.valid)
            {
                CustomMessageBox.Show("No SRTM data for this area", Strings.ERROR);
                return;
            }

            MAVLink.mavlink_set_gps_global_origin_t go = new MAVLink.mavlink_set_gps_global_origin_t()
            {
                latitude = (int) (MouseDownStart.Lat * 1e7),
                longitude = (int) (MouseDownStart.Lng * 1e7),
                altitude = (int) alt.alt * 1000, // in mm
                target_system = MainV2.comPort.MAV.sysid
            };

            MainV2.comPort.sendPacket(go, MainV2.comPort.MAV.sysid, MainV2.comPort.MAV.compid);
        }

        private void setGStreamerSourceToolStripMenuItem_Click(object sender, EventArgs e)
        {
            string url = Settings.Instance["gstreamer_url"] != null
                ? Settings.Instance["gstreamer_url"]
                : @"videotestsrc ! video/x-raw, width=1280, height=720, framerate=30/1 ! videoconvert ! video/x-raw,format=BGRA ! appsink name=outsink";

            if (DialogResult.OK == InputBox.Show("GStreamer url",
                "Enter the source pipeline\nEnsure the final payload is ! videoconvert ! video/x-raw,format=BGRA ! appsink name=outsink",
                ref url))
            {
                Settings.Instance["gstreamer_url"] = url;

                GStreamer.GstLaunch = GStreamer.LookForGstreamer();

                if (!GStreamer.GstLaunchExists)
                {
                    GStreamerUI.DownloadGStreamer();

                    if (!GStreamer.GstLaunchExists)
                    {
                        return;
                    }
                }

                try
                {
                    hudGStreamer.Start(url);
                }
                catch (Exception ex)
                {
                    CustomMessageBox.Show(ex.ToString(), Strings.ERROR);
                }
            }
            else
            {
                hudGStreamer.Stop();
            }
        }

        private async void setHomeHereToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (MainV2.comPort.BaseStream.IsOpen)
            {
                try
                {
                    var alt = srtm.getAltitude(MouseDownStart.Lat, MouseDownStart.Lng);

                    if (alt.currenttype != srtm.tiletype.valid && alt.currenttype != srtm.tiletype.ocean)
                    {
                        CustomMessageBox.Show("No SRTM data for this area", Strings.ERROR);
                        return;
                    }

                    if (CustomMessageBox.Show(
                            "This will reset the onboard home position (effects RTL etc). Are you Sure?",
                            "Are you sure?", CustomMessageBox.MessageBoxButtons.OKCancel) ==
                        CustomMessageBox.DialogResult.OK)
                    {
                        MainV2.comPort.doCommandInt((byte) MainV2.comPort.sysidcurrent,
                            (byte) MainV2.comPort.compidcurrent,
                            MAVLink.MAV_CMD.DO_SET_HOME, 0, 0, 0, 0, (int)(MouseDownStart.Lat * 1e7),
                            (int)(MouseDownStart.Lng * 1e7), (float)(alt.alt));
                    }

                    await MainV2.comPort.getHomePositionAsync((byte) MainV2.comPort.sysidcurrent,
                        (byte) MainV2.comPort.compidcurrent);
                }
                catch
                {
                    CustomMessageBox.Show(Strings.CommandFailed, Strings.ERROR);
                }
            }
        }

        private void setMapBearing()
        {
            BeginInvoke((Action) delegate { gMapControl1.Bearing = (int) ((MainV2.comPort.MAV.cs.yaw + 360) % 360); });
        }

        private void setMJPEGSourceToolStripMenuItem_Click(object sender, EventArgs e)
        {
            string url = Settings.Instance["mjpeg_url"] != null
                ? Settings.Instance["mjpeg_url"]
                : @"http://127.0.0.1:56781/map.jpg";

            if (DialogResult.OK == InputBox.Show("Mjpeg url", "Enter the url to the mjpeg source url", ref url))
            {
                Settings.Instance["mjpeg_url"] = url;

                CaptureMJPEG.Stop();

                CaptureMJPEG.URL = url;

                CaptureMJPEG.runAsync();
            }
            else
            {
                CaptureMJPEG.Stop();
            }
        }

        private void setQuickViewRowsCols(string cols, string rows)
        {
            tableLayoutPanelQuick.PerformLayout();
            tableLayoutPanelQuick.SuspendLayout();
            tableLayoutPanelQuick.ColumnCount = Math.Max(1, int.Parse(cols));
            tableLayoutPanelQuick.RowCount = Math.Max(1, int.Parse(rows));

            Settings.Instance["quickViewRows"] = tableLayoutPanelQuick.RowCount.ToString();
            Settings.Instance["quickViewCols"] = tableLayoutPanelQuick.ColumnCount.ToString();

            int total = tableLayoutPanelQuick.ColumnCount * tableLayoutPanelQuick.RowCount;

            // clean up extra
            var ctls = tableLayoutPanelQuick.Controls.Select(a => (Control) a).ToList();
            // remove those in row/cols outside our selection
            ctls.Select(a =>
            {
                try
                {
                    if (a == null)
                        return default(TableLayoutPanelCellPosition);
                    var pos = tableLayoutPanelQuick.GetPositionFromControl((Control) a);
                    if (pos.Column >= tableLayoutPanelQuick.ColumnCount)
                    {
                        tableLayoutPanelQuick.Controls.Remove((Control) a);
                    }
                    else if (pos.Row >= tableLayoutPanelQuick.RowCount)
                    {
                        tableLayoutPanelQuick.Controls.Remove((Control) a);
                    }

                    return pos;
                }
                catch (Exception ex)
                {
                    log.Error(ex);
                    return default(TableLayoutPanelCellPosition);
                }
            }).ToList();
            //randomiser for colors
            Random random = new Random();
            var controlCount = tableLayoutPanelQuick.Controls;
            ////if the amount on the quickView Tab decreases, clear the colors List
            if ((controlCount.Count <= total || controlCount.Count >= total) && listQuickView.Count() % 16 == 0)
            {
                listQuickView.Clear();
            }
            // add extra
            while (total > tableLayoutPanelQuick.Controls.Count)
            {
                //Variable to Set the name of the quickView Control/s
                var NameQuickView = "quickView" +  (controlCount.Count + 1);

                //if the 9 colors are equal in each list, then reset the colors in listQV
                if ((listQuickView.ToList().OrderBy(x => Name) == colorsForDefaultQuickView.ToList().OrderBy(x => Name)) || (listQuickView.Count == colorsForDefaultQuickView.Length))
                {
                    listQuickView.Clear();
                }

                //Generate a random color
                var randomColorQuickView = colorsForDefaultQuickView[random.Next(colorsForDefaultQuickView.Length)];

                //If the list contains the random color and the listQV list contains more than one item, exclude the color from the next color to be chosen
                if (listQuickView.Contains(randomColorQuickView) && listQuickView.ToList().Count() > 1)
                {
                    //Change random color to be the next available color
                    var differentColorQuickView = colorsForDefaultQuickView[random.Next(colorsForDefaultQuickView.Length)];
                    //Variable to find the items that are in colorsForDefault array, but are not in ListQV list
                    var colorsRemaining = colorsForDefaultQuickView.Except(listQuickView);

                    //if differentColor is the same as randomColor, then select the next item in the list of colors which are still available to be chosen from.
                    if (randomColorQuickView == differentColorQuickView)
                    {
                        //make differentColor the next availaible color in the list of colors which are not yet in the listQV list
                        differentColorQuickView = colorsRemaining.FirstOrDefault();
                    }
                    //if randomColor is not equal to differentColor, and check if either color is contained in the list of colors(listQV)
                    if (randomColorQuickView != differentColorQuickView && (listQuickView.Contains(differentColorQuickView) || listQuickView.Contains(randomColorQuickView)))
                    {
                        //if differentColor and randomColor are both in the listQV list, then get the next color of remaining colors which have not yet been used
                        if ((listQuickView.Contains(differentColorQuickView) && listQuickView.Contains(randomColorQuickView)))
                        {
                            //assign the next color available to the differentColorVariable
                            differentColorQuickView = colorsRemaining.FirstOrDefault();
                        }
                        else
                        {
                            differentColorQuickView = colorsRemaining.FirstOrDefault();
                        }
                    }
                    //assign the differentColor to randomColor
                    randomColorQuickView = differentColorQuickView;
                    //add the new randomColor into the list of colors(listQV)
                    listQuickView.Add(randomColorQuickView);
                    //if the list does not yet contain the randomColor, then add the random color into the list(listQV)
                    if (!listQuickView.Contains(randomColorQuickView))
                    {
                        listQuickView.Add(randomColorQuickView);
                    }
                }
                //if the random color is not in the list of Colors, then add it to the list
                else if (!listQuickView.Contains(randomColorQuickView))
                {
                    //add the color to a list
                    listQuickView.Add(randomColorQuickView);
                }
                //assigning the Name and NumberColor accordingly.
                var QV = new QuickView()
                {
                    Name = NameQuickView,
                    numberColor = randomColorQuickView,
                };
                if (!MainV2.DisplayConfiguration.lockQuickView)
                    QV.DoubleClick += quickView_DoubleClick;
                QV.ContextMenuStrip = contextMenuStripQuickView;
                QV.Dock = DockStyle.Fill;
                QV.numberColorBackup = QV.numberColor;
                QV.number = 0;

                tableLayoutPanelQuick.Controls.Add(QV);
                QV.Invalidate();
            }
            //clear the listQV when the count of the list is divisible by 16
            if (listQuickView.ToList().Count % 16 == 0)
            {
                listQuickView.Clear();
            }
            for (int i = 0; i < tableLayoutPanelQuick.ColumnCount; i++)
            {
                if (tableLayoutPanelQuick.ColumnStyles.Count <= i)
                    tableLayoutPanelQuick.ColumnStyles.Add(new ColumnStyle());
                tableLayoutPanelQuick.ColumnStyles[i].SizeType = SizeType.Percent;
                tableLayoutPanelQuick.ColumnStyles[i].Width = 100.0f / tableLayoutPanelQuick.ColumnCount;
            }

            for (int j = 0; j < tableLayoutPanelQuick.RowCount; j++)
            {
                if (tableLayoutPanelQuick.RowStyles.Count <= j)
                    tableLayoutPanelQuick.RowStyles.Add(new RowStyle());
                tableLayoutPanelQuick.RowStyles[j].SizeType = SizeType.Percent;
                tableLayoutPanelQuick.RowStyles[j].Height = 100.0f / tableLayoutPanelQuick.RowCount;
            }

            tableLayoutPanelQuick.Controls.ForEach(a => ((Control) a).Invalidate());

            tableLayoutPanelQuick.ResumeLayout(true);
        }

        bool setupPropertyInfo(ref PropertyInfo input, string name, object source)
        {
            Type test = source.GetType();

            foreach (var field in test.GetProperties())
            {
                if (field.Name == name)
                {
                    input = field;
                    return true;
                }
            }

            return false;
        }

        private void setViewCountToolStripMenuItem_Click(object sender, EventArgs e)
        {
            string cols = "2", rows = "3";

            if (Settings.Instance["quickViewRows"] != null)
            {
                rows = Settings.Instance["quickViewRows"];
                cols = Settings.Instance["quickViewCols"];
            }

            if (InputBox.Show("Columns", "Enter number of columns to have.", ref cols) == DialogResult.OK)
            {
                if (InputBox.Show("Rows", "Enter number of rows to have.", ref rows) == DialogResult.OK)
                {
                    if (rows.IsNumber() && cols.IsNumber())
                        setQuickViewRowsCols(cols, rows);

                    Activate();
                }
            }
        }

        private void startCameraToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (MainV2.MONO)
                return;
            if (MainV2.cam == null)
            {
                try
                {
                    MainV2.cam = new Capture(Settings.Instance.GetInt32("video_device"), new AMMediaType());

                    MainV2.cam.Start();

                    MainV2.cam.camimage += new CamImage(cam_camimage);
                }
                catch (Exception ex)
                {
                    CustomMessageBox.Show("Camera Fail: " + ex.ToString(), Strings.ERROR);
                }
            }
        }

        private void stopRecordToolStripMenuItem_Click(object sender, EventArgs e)
        {
            recordHudToAVIToolStripMenuItem.Text = "Start Recording";

            try
            {
                if (aviwriter != null)
                    aviwriter.avi_close();
            }
            catch (Exception ex)
            {
                CustomMessageBox.Show(Strings.ERROR + " " + ex, Strings.ERROR);
            }

            aviwriter = null;
        }

        private void SwapHud1AndMap()
        {
            if (this.huddropout)
                return;

            MainH.Panel2.SuspendLayout();

            if (this.SubMainLeft.Panel1.Controls.Contains(hud1))
            {
                Settings.Instance["HudSwap"] = "true";
                MainH.Panel2.Controls.Add(hud1);
                SubMainLeft.Panel1.Controls.Add(tableMap);
            }
            else
            {
                Settings.Instance["HudSwap"] = "false";
                MainH.Panel2.Controls.Add(tableMap);
                SubMainLeft.Panel1.Controls.Add(hud1);
            }

            MainH.Panel2.ResumeLayout();
        }

        private void swapWithMapToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SwapHud1AndMap();
        }

        void tabControl1_DrawItem(object sender, DrawItemEventArgs e)
        {
            // Draw the background of the ListBox control for each item.
            //e.DrawBackground();
            // Define the default color of the brush as black.
            Brush myBrush = Brushes.Black;

            LinearGradientBrush linear = new LinearGradientBrush(e.Bounds, Color.FromArgb(0x94, 0xc1, 0x1f),
                Color.FromArgb(0xcd, 0xe2, 0x96), LinearGradientMode.Vertical);

            e.Graphics.FillRectangle(linear, e.Bounds);

            // Draw the current item text based on the current Font
            // and the custom brush settings.
            e.Graphics.DrawString(((TabControl) sender).TabPages[e.Index].Text,
                e.Font, myBrush, e.Bounds, StringFormat.GenericDefault);
            // If the ListBox has focus, draw a focus rectangle around the selected item.
            e.DrawFocusRectangle();
        }

        private void tabControl1_SelectedIndexChanged(object sender, EventArgs e)
        {
            Messagetabtimer.Stop();

            if (tabControlactions.SelectedTab == tabStatus)
            {
                tabControlactions.Visible = false;
                tabStatus.Visible = false;
                tabStatus_Resize(sender, e);
                tabStatus.Visible = true;
                tabControlactions.Visible = true;
            }
            else if (tabControlactions.SelectedTab == tabPagemessages)
            {
                Messagetabtimer.Start();
            }
            else
            {
                // foreach (Control temp in tabStatus.Controls)
                // {
                //   temp.DataBindings.Clear();
                //  temp.Dispose();
                //  tabStatus.Controls.Remove(temp);
                // }

                if (tabControlactions.SelectedTab == tabQuick)
                {
                }
            }
        }

        private void tabPage1_Resize(object sender, EventArgs e)
        {
            int mywidth, myheight;

            // localize it
            Control tabGauges = sender as Control;

            float scale = tabGauges.Width / (float) tabGauges.Height;

            if (scale > 0.5 && scale < 1.9)
            {
                // square
                Gvspeed.Visible = true;

                if (tabGauges.Height < tabGauges.Width)
                    myheight = tabGauges.Height / 2;
                else
                    myheight = tabGauges.Width / 2;

                Gvspeed.Height = myheight;
                Gspeed.Height = myheight;
                Galt.Height = myheight;
                Gheading.Height = myheight;

                Gvspeed.Location = new Point(0, 0);
                Gspeed.Location = new Point(Gvspeed.Right, 0);


                Galt.Location = new Point(0, Gspeed.Bottom);
                Gheading.Location = new Point(Galt.Right, Gspeed.Bottom);

                return;
            }

            if (tabGauges.Width < 500)
            {
                Gvspeed.Visible = false;
                mywidth = tabGauges.Width / 3;

                Gspeed.Height = mywidth;
                Galt.Height = mywidth;
                Gheading.Height = mywidth;

                Gspeed.Location = new Point(0, 0);
            }
            else
            {
                Gvspeed.Visible = true;
                mywidth = tabGauges.Width / 4;

                Gvspeed.Height = mywidth;
                Gspeed.Height = mywidth;
                Galt.Height = mywidth;
                Gheading.Height = mywidth;

                Gvspeed.Location = new Point(0, 0);
                Gspeed.Location = new Point(Gvspeed.Right, 0);
            }

            Galt.Location = new Point(Gspeed.Right, 0);
            Gheading.Location = new Point(Galt.Right, 0);
        }

        private void tabQuick_Resize(object sender, EventArgs e)
        {
            tableLayoutPanelQuick.Width = tabQuick.Width;
            tableLayoutPanelQuick.AutoScroll = false;
        }

        void tabStatus_Resize(object sender, EventArgs e)
        {
        }

        private void takeOffToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (MainV2.comPort.BaseStream.IsOpen)
            {
                string alt = Settings.Instance["takeoff_alt", "5"];

                if (DialogResult.Cancel == InputBox.Show("Enter Alt", "Enter Takeoff Alt", ref alt))
                    return;

                var altf = float.Parse(alt, CultureInfo.InvariantCulture);

                Settings.Instance["takeoff_alt"] = altf.ToString();

                MainV2.comPort.setMode("GUIDED");

                try
                {
                    MainV2.comPort.doCommand((byte) MainV2.comPort.sysidcurrent, (byte) MainV2.comPort.compidcurrent,
                        MAVLink.MAV_CMD.TAKEOFF, 0, 0, 0, 0, 0, 0, altf);
                }
                catch
                {
                    CustomMessageBox.Show(Strings.CommandFailed, Strings.ERROR);
                }
            }
        }

        private void ZedGraphTimer_Tick(object sender, EventArgs e)
        {
            try
            {
                // Make sure that the curvelist has at least one curve
                if (zg1.GraphPane.CurveList.Count <= 0)
                    return;

                // Get the first CurveItem in the graph
                LineItem curve = zg1.GraphPane.CurveList[0] as LineItem;
                if (curve == null)
                    return;

                // Get the PointPairList
                IPointListEdit list = curve.Points as IPointListEdit;
                // If this is null, it means the reference at curve.Points does not
                // support IPointListEdit, so we won't be able to modify it
                if (list == null)
                    return;

                // Time is measured in seconds
                double time = (Environment.TickCount - tickStart) / 1000.0;

                // Keep the X scale at a rolling 30 second interval, with one
                // major step between the max X value and the end of the axis
                Scale xScale = zg1.GraphPane.XAxis.Scale;
                if (time > xScale.Max - xScale.MajorStep)
                {
                    xScale.Max = time + xScale.MajorStep;
                    xScale.Min = xScale.Max - 10.0;
                }

                // Make sure the Y axis is rescaled to accommodate actual data
                zg1.AxisChange();

                // Force a redraw

                zg1.Invalidate();
            }
            catch
            {
            }
        }

        private void tracklog_Scroll(object sender, EventArgs e)
        {
            try
            {
                BUT_clear_track_Click(sender, e);

                MainV2.comPort.lastlogread = DateTime.MinValue;
                MainV2.comPort.MAV.cs.ResetInternals();

                if (MainV2.comPort.logplaybackfile != null)
                    MainV2.comPort.logplaybackfile.BaseStream.Position =
                        (long) (MainV2.comPort.logplaybackfile.BaseStream.Length * (tracklog.Value / 100.0));

                updateLogPlayPosition(false);
            }
            catch
            {
            } // ignore any invalid
        }

        private void triggerCameraToolStripMenuItem_Click(object sender, EventArgs e)
        {
            try
            {
                MainV2.comPort.setDigicamControl(true);
            }
            catch
            {
                CustomMessageBox.Show(Strings.CommandFailed, Strings.ERROR);
            }
        }

        private void TRK_zoom_Scroll(object sender, EventArgs e)
        {
            try
            {
                if (gMapControl1.MaxZoom + 1 == (double) TRK_zoom.Value)
                {
                    gMapControl1.Zoom = TRK_zoom.Value - .1;
                    Zoomlevel.Value = Convert.ToDecimal(TRK_zoom.Value - .1);
                }
                else
                {
                    gMapControl1.Zoom = TRK_zoom.Value;
                    Zoomlevel.Value = Convert.ToDecimal(TRK_zoom.Value);
                }

                UpdateOverlayVisibility();
            }
            catch
            {
            }
        }

        private void txt_messagebox_TextChanged(object sender, EventArgs e)
        {
            txt_messagebox.Select(txt_messagebox.Text.Length, 0);
            txt_messagebox.ScrollToCaret();
        }

        private void updateBindingSource()
        {
            //  run at 10 hz.
            if (lastscreenupdate.AddMilliseconds(100) < DateTime.UtcNow)
            {
                lock (updateBindingSourcelock)
                {
                    // this is an attempt to prevent an invoke queue on the binding update on slow machines
                    if (updateBindingSourcecount > 0)
                    {
                        if (lastscreenupdate < DateTime.UtcNow.AddSeconds(-5))
                        {
                            updateBindingSourcecount = 0;
                        }

                        return;
                    }

                    updateBindingSourcecount++;
                    updateBindingSourceThreadName = Thread.CurrentThread.Name;
                }

                if(Disposing)
                    return;

                this.BeginInvokeIfRequired(delegate
                {
                    updateBindingSourceWork();

                    lock (updateBindingSourcelock)
                    {
                        updateBindingSourcecount--;
                    }
                });
            }
        }

        private void updateBindingSourceWork()
        {
            try
            {
                if (this.Visible && !this.IsDisposed)
                {
                    //Console.Write("bindingSource1 ");
                    MainV2.comPort.MAV.cs.UpdateCurrentSettings(bindingSource1.UpdateDataSource(MainV2.comPort.MAV.cs));
                    //Console.Write("bindingSourceHud ");
                    MainV2.comPort.MAV.cs.UpdateCurrentSettings(
                        bindingSourceHud.UpdateDataSource(MainV2.comPort.MAV.cs));
                    //Console.WriteLine("DONE ");

                    if (tabControlactions.SelectedTab == tabStatus)
                    {
                        MainV2.comPort.MAV.cs.UpdateCurrentSettings(
                            bindingSourceStatusTab.UpdateDataSource(MainV2.comPort.MAV.cs));
                        this.tabStatus.Invalidate();
                    }
                    else if (tabControlactions.SelectedTab == tabQuick)
                    {
                        MainV2.comPort.MAV.cs.UpdateCurrentSettings(
                            bindingSourceQuickTab.UpdateDataSource(MainV2.comPort.MAV.cs));
                    }
                    else if (tabControlactions.SelectedTab == tabGauges)
                    {
                        MainV2.comPort.MAV.cs.UpdateCurrentSettings(
                            bindingSourceGaugesTab.UpdateDataSource(MainV2.comPort.MAV.cs));
                    }
                    else if (tabControlactions.SelectedTab == tabPagePreFlight)
                    {
                        MainV2.comPort.MAV.cs.UpdateCurrentSettings(
                            bindingSourceGaugesTab.UpdateDataSource(MainV2.comPort.MAV.cs));
                    }
                    else if (tabControlactions.SelectedTab == tabPayload)
                    {
                        MainV2.comPort.MAV.cs.UpdateCurrentSettings(
                            bindingSourcePayloadTab.UpdateDataSource(MainV2.comPort.MAV.cs));
                    }
                }
                else
                {
                    //Console.WriteLine("Null Binding");
                    MainV2.comPort.MAV.cs.UpdateCurrentSettings(
                        bindingSourceHud.UpdateDataSource(MainV2.comPort.MAV.cs));
                }
                //if the tab detached wi have to update it
                if (tabQuickDetached) MainV2.comPort.MAV.cs.UpdateCurrentSettings(bindingSourceQuickTab.UpdateDataSource(MainV2.comPort.MAV.cs));

                lastscreenupdate = DateTime.UtcNow;
            }
            catch (Exception ex)
            {
                log.Error(ex);
                Tracking.AddException(ex);
            }
        }

        // to prevent cross thread calls while in a draw and exception
        private void updateClearMissionRouteMarkers()
        {
            // not async
            BeginInvoke((Action) delegate
            {
                polygons.Routes.Clear();
                polygons.Markers.Clear();
                routes.Markers.Clear();
            });
        }

        // to prevent cross thread calls while in a draw and exception
        private void updateClearRoutes()
        {
            // not async
            BeginInvoke((Action) delegate
            {
                routes.Routes.Clear();
                routes.Routes.Add(route);
            });
        }

        private void updateClearRoutesMarkers()
        {
            BeginInvoke((Action) delegate { routes.Markers.Clear(); });
        }

        private void updateLogPlayPosition(bool updatetracklog = true)
        {
            BeginInvoke((Action) delegate
            {
                try
                {
                    if (updatetracklog && tracklog.Visible)
                    {
                        // prevent event fire
                        tracklog.ValueChanged -= tracklog_Scroll;
                        tracklog.Value = (int) (MainV2.comPort.logplaybackfile.BaseStream.Position /
                            (double) MainV2.comPort.logplaybackfile.BaseStream.Length * 100);
                        tracklog.ValueChanged += tracklog_Scroll;
                    }

                    if (lbl_logpercent.Visible)
                        lbl_logpercent.Text =
                            (MainV2.comPort.logplaybackfile.BaseStream.Position /
                             (double) MainV2.comPort.logplaybackfile.BaseStream.Length).ToString("0.00%");

                    if (lbl_playbackspeed.Visible)
                        lbl_playbackspeed.Text = "x " + LogPlayBackSpeed;
                }
                catch
                {
                }
            });
        }

        private void updateMapPosition(PointLatLng currentloc)
        {
            BeginInvoke((Action) delegate
            {
                try
                {
                    if (lastmapposchange.Second != DateTime.Now.Second)
                    {
                        if (Math.Abs(currentloc.Lat - gMapControl1.Position.Lat) > 0.0001 ||
                            Math.Abs(currentloc.Lng - gMapControl1.Position.Lng) > 0.0001)
                        {
                            gMapControl1.Position = currentloc;
                        }

                        lastmapposchange = DateTime.Now;
                    }

                    //hud1.Refresh();
                }
                catch
                {
                }
            });
        }

        private void updateMapZoom(int zoom)
        {
            BeginInvoke((Action) delegate
            {
                try
                {
                    gMapControl1.Zoom = zoom;
                }
                catch
                {
                }
            });
        }

        void UpdateOverlayVisibility()
        {
            // change overlay visability
            if (gMapControl1.ViewArea != null)
            {
                var bounds = gMapControl1.ViewArea;
                bounds.Inflate(1, 1);

                foreach (var poly in kmlpolygons.Polygons)
                {
                    if (bounds.Contains(poly.Points[0]))
                        poly.IsVisible = true;
                    else
                        poly.IsVisible = false;
                }
            }
        }

        private void updatePlayPauseButton(bool playing)
        {
            if (playing)
            {
                if (BUT_playlog.Text == "Pause")
                    return;

                BeginInvoke((Action) delegate
                {
                    try
                    {
                        BUT_playlog.Text = "Pause";
                    }
                    catch
                    {
                    }
                });
            }
            else
            {
                if (BUT_playlog.Text == "Play")
                    return;

                BeginInvoke((Action) delegate
                {
                    try
                    {
                        BUT_playlog.Text = "Play";
                    }
                    catch
                    {
                    }
                });
            }
        }

        private void updateRoutePosition()
        {
            // not async
            BeginInvoke((Action) delegate { gMapControl1.UpdateRouteLocalPosition(route); });
        }

        private void zg1_DoubleClick(object sender, EventArgs e)
        {

            var selectform = new Form
            {
                Name = "select",
                Width = 50,
                Height = 50,
                Text = "Display This",
                AutoSize = true,
                StartPosition = FormStartPosition.CenterParent,
                MaximizeBox = false,
                MinimizeBox = false,
                AutoScroll = true
            };

            ThemeManager.ApplyThemeTo(selectform);

            object thisBoxed = MainV2.comPort.MAV.cs;
            Type test = thisBoxed.GetType();

            int max_length = 0;
            List<(string name, string desc)> fields = new List<(string, string)>();

            foreach (var field in test.GetProperties())
            {
                // field.Name has the field's name.
                object fieldValue = field.GetValue(thisBoxed, null); // Get value
                if (fieldValue == null)
                    continue;

                if (!fieldValue.IsNumber())
                    continue;

                if (field.Name.Contains("customfield"))
                {
                    if (CurrentState.custom_field_names.ContainsKey(field.Name))
                    {
                        string name = CurrentState.custom_field_names[field.Name];
                        max_length = Math.Max(max_length, TextRenderer.MeasureText(name, selectform.Font).Width);
                        fields.Add((field.Name, name));
                    }
                }
                else
                {
                    max_length = Math.Max(max_length, TextRenderer.MeasureText(field.Name, selectform.Font).Width);
                    fields.Add((field.Name, field.Name));
                }
            }

            max_length += 25;
            fields.Sort((a, b) => {
                var ans = CurrentState.GetGroupText(a.name).CompareTo(CurrentState.GetGroupText(b.name));
                if (ans == 0) return a.Item2.CompareTo(b.Item2);
                return ans;
            });

            int col_count = (int) (Screen.FromControl(this).Bounds.Width * 0.8f) / max_length;
            int row_count = fields.Count / col_count + ((fields.Count % col_count == 0) ? 0 : 1);
            int row_height = 20;

            selectform.SuspendLayout();

            (string name, string desc) last = ("", "");

            int i = 1;
            foreach (var field in fields)
            {
                CheckBox chk_box = new CheckBox();

                ThemeManager.ApplyThemeTo(chk_box);

                if (list1item != null && list1item.Name == field.name)
                {
                    chk_box.Checked = true;
                    chk_box.BackColor = Color.Green;
                }

                if (list2item != null && list2item.Name == field.name)
                {
                    chk_box.Checked = true;
                    chk_box.BackColor = Color.Green;
                }

                if (list3item != null && list3item.Name == field.name)
                {
                    chk_box.Checked = true;
                    chk_box.BackColor = Color.Green;
                }

                if (list4item != null && list4item.Name == field.name)
                {
                    chk_box.Checked = true;
                    chk_box.BackColor = Color.Green;
                }

                if (list5item != null && list5item.Name == field.name)
                {
                    chk_box.Checked = true;
                    chk_box.BackColor = Color.Green;
                }

                if (list6item != null && list6item.Name == field.name)
                {
                    chk_box.Checked = true;
                    chk_box.BackColor = Color.Green;
                }

                if (list7item != null && list7item.Name == field.name)
                {
                    chk_box.Checked = true;
                    chk_box.BackColor = Color.Green;
                }

                if (list8item != null && list8item.Name == field.name)
                {
                    chk_box.Checked = true;
                    chk_box.BackColor = Color.Green;
                }

                if (list9item != null && list9item.Name == field.name)
                {
                    chk_box.Checked = true;
                    chk_box.BackColor = Color.Green;
                }

                if (list10item != null && list10item.Name == field.name)
                {
                    chk_box.Checked = true;
                    chk_box.BackColor = Color.Green;
                }
                if (list11item != null && list11item.Name == field.name)
                {
                    chk_box.Checked = true;
                    chk_box.BackColor = Color.Green;
                }

                if (list12item != null && list12item.Name == field.name)
                {
                    chk_box.Checked = true;
                    chk_box.BackColor = Color.Green;
                }

                if (list13item != null && list13item.Name == field.name)
                {
                    chk_box.Checked = true;
                    chk_box.BackColor = Color.Green;
                }

                if (list14item != null && list14item.Name == field.name)
                {
                    chk_box.Checked = true;
                    chk_box.BackColor = Color.Green;
                }

                if (list15item != null && list15item.Name == field.name)
                {
                    chk_box.Checked = true;
                    chk_box.BackColor = Color.Green;
                }

                if (list16item != null && list16item.Name == field.name)
                {
                    chk_box.Checked = true;
                    chk_box.BackColor = Color.Green;
                }

                if (list17item != null && list17item.Name == field.name)
                {
                    chk_box.Checked = true;
                    chk_box.BackColor = Color.Green;
                }

                if (list18item != null && list18item.Name == field.name)
                {
                    chk_box.Checked = true;
                    chk_box.BackColor = Color.Green;
                }

                if (list19item != null && list19item.Name == field.name)
                {
                    chk_box.Checked = true;
                    chk_box.BackColor = Color.Green;
                }

                if (list20item != null && list20item.Name == field.name)
                {
                    chk_box.Checked = true;
                    chk_box.BackColor = Color.Green;
                }

                if (CurrentState.GetGroupText(field.name) != CurrentState.GetGroupText(last.name))
                {
                    selectform.Controls.Add(new System.Windows.Forms.Label()
                    {
                        Text = CurrentState.GetGroupText(field.name),
                        Location = new Point(5 + (i / row_count) * (max_length + 5), 2 + (i % row_count) * row_height)
                    });
                    i++;
                }

                chk_box.Text = field.desc;
                chk_box.Name = field.name;
                chk_box.Tag = "custom";
                chk_box.Location = new Point(5 + (i / row_count) * (max_length + 5), 2 + (i % row_count) * row_height);
                chk_box.Size = new Size(120, 20);
                chk_box.CheckedChanged += chk_box_tunningCheckedChanged;
                chk_box.MouseDown += Chk_box_tunningMouseDown;
                chk_box.AutoSize = true;

                selectform.Controls.Add(chk_box);
                i++;

                last = field;
            }

            selectform.ResumeLayout();

            selectform.Shown += (o, args) =>
            {
                selectform.Controls.ForEach(a =>
                {
                    if (a is CheckBox && ((CheckBox) a).Checked)
                        ((CheckBox) a).BackColor = Color.Green;
                });
            };

            selectform.Show();
        }

        private void Chk_box_tunningMouseDown(object sender, MouseEventArgs e)
        {
            tuningwasrightclick = e.Button == MouseButtons.Right;
            if (tuningwasrightclick)
            {
                var chk = sender as CheckBox;
                if (chk != null)
                    chk.Checked = !chk.Checked;
            }
        }

        private void Zoomlevel_ValueChanged(object sender, EventArgs e)
        {
            try
            {
                if (gMapControl1.MaxZoom + 1 == (double) Zoomlevel.Value)
                {
                    gMapControl1.Zoom = (double) Zoomlevel.Value - .1;
                    TRK_zoom.Value = (float)Zoomlevel.Value - (float).1;
                }
                else
                {
                    gMapControl1.Zoom = (double) Zoomlevel.Value;
                    TRK_zoom.Value = (float)Zoomlevel.Value;
                }
            }
            catch
            {
            }
        }

        private void BUT_georefimage_Click(object sender, EventArgs e)
        {
            new Georefimage().Show();
        }

        private void flyToCoordsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var location = "";
            InputBox.Show("Enter Fly To Coords", "Please enter the coords 'lat;long;alt' or 'lat;long'", ref location);

            byte frame = (byte)MAVLink.MAV_FRAME.GLOBAL_RELATIVE_ALT;
            if (!MainV2.comPort.MAV.GuidedMode.Equals(new MAVLink.mavlink_mission_item_int_t()))
            {
                frame = MainV2.comPort.MAV.GuidedMode.frame;
            }
            else if (Settings.Instance.ContainsKey("guided_alt_frame"))
            {
                byte.TryParse(Settings.Instance["guided_alt_frame"], out frame);
            }

            var split = location.Split(';');

            if (split.Length == 3)
            {
                var lat = float.Parse(split[0], CultureInfo.InvariantCulture);
                var lng = float.Parse(split[1], CultureInfo.InvariantCulture);
                var alt = float.Parse(split[2], CultureInfo.InvariantCulture);

                var plla = new PointLatLngAlt(lat, lng, alt);

                Locationwp gotohere = new Locationwp();

                gotohere.id = (ushort) MAVLink.MAV_CMD.WAYPOINT;
                gotohere.alt = (float) plla.Alt / CurrentState.multiplieralt; // back to m
                gotohere.lat = (plla.Lat);
                gotohere.lng = (plla.Lng);
                gotohere.frame = frame;

                try
                {
                    MainV2.comPort.setGuidedModeWP(gotohere);
                }
                catch (Exception ex)
                {
                    CustomMessageBox.Show(Strings.CommandFailed + ex.Message, Strings.ERROR);
                }
            }
            else if (split.Length == 2)
            {
                var lat = float.Parse(split[0], CultureInfo.InvariantCulture);
                var lng = float.Parse(split[1], CultureInfo.InvariantCulture);
                var alt = srtm.getAltitude(MouseDownStart.Lat, MouseDownStart.Lng).alt / CurrentState.multiplieralt;

                var plla = new PointLatLngAlt(lat, lng, alt);

                Locationwp gotohere = new Locationwp();

                gotohere.id = (ushort) MAVLink.MAV_CMD.WAYPOINT;
                gotohere.alt = MainV2.comPort.MAV.GuidedMode.z; // back to m
                gotohere.lat = (plla.Lat);
                gotohere.lng = (plla.Lng);
                gotohere.frame = frame;

                try
                {
                    MainV2.comPort.setGuidedModeWP(gotohere);
                }
                catch (Exception ex)
                {
                    CustomMessageBox.Show(Strings.CommandFailed + ex.Message, Strings.ERROR);
                }
            }
            else
            {
                CustomMessageBox.Show(Strings.InvalidField, Strings.ERROR);
            }
        }

        private void poiatcoordsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var location = "";
            InputBox.Show("Enter POI Coords", "Please enter the coords 'lat;long;alt' or 'lat;long'", ref location);

            var split = location.Split(';');

            if (split.Length == 3)
            {
                var lat = float.Parse(split[0], CultureInfo.InvariantCulture);
                var lng = float.Parse(split[1], CultureInfo.InvariantCulture);
                var alt = float.Parse(split[2], CultureInfo.InvariantCulture);

                POI.POIAdd(new PointLatLngAlt(lat, lng, alt));
            }
            else if (split.Length == 2)
            {
                var lat = float.Parse(split[0], CultureInfo.InvariantCulture);
                var lng = float.Parse(split[1], CultureInfo.InvariantCulture);
                var alt = srtm.getAltitude(MouseDownStart.Lat, MouseDownStart.Lng).alt / CurrentState.multiplieralt;

                POI.POIAdd(new PointLatLngAlt(lat, lng, alt));
            }
            else
            {
                CustomMessageBox.Show(Strings.InvalidField, Strings.ERROR);
            }
        }

        private void hud1_Load(object sender, EventArgs e)
        {

        }

        private void tabStatus_Paint(object sender, PaintEventArgs e)
        {
            var bmp = new Bitmap(tabStatus.DisplayRectangle.Width, tabStatus.DisplayRectangle.Height);
            var g = Graphics.FromImage(bmp);
            g.Clear(Color.Transparent);

            int x = 10;
            int y = 10;

            var list = MainV2.comPort.MAV.cs.GetItemList(true);
            var cs = bindingSourceStatusTab.Current as CurrentState;
            var br = new SolidBrush(tabStatus.ForeColor);

            foreach (var field in list)
            {
                g.DrawString(field, this.Font, br, new RectangleF(x, y, 120, 15));

                if (cs != null)
                    g.DrawString(typeof(CurrentState).GetProperty(field).GetValue(cs)?.ToString(), this.Font,
                        br, new RectangleF(x + 120, y, 50, 15));

                x += 0;
                y += 15;

                if (y > tabStatus.Height - 30)
                {
                    x += 190;
                    y = 10;
                }
            }

            if (tabStatus.AutoScrollMinSize.Width < x)
            {
                typeof(Panel).InvokeMember("DoubleBuffered", BindingFlags.SetProperty
                                                             | BindingFlags.Instance | BindingFlags.NonPublic, null,
                    tabStatus, new object[] { true });

                tabStatus.AutoScrollMinSize = new Size(x + 164, 0);
            }
            e.Graphics.TranslateTransform(tabStatus.AutoScrollPosition.X,
                tabStatus.AutoScrollPosition.Y);
            e.Graphics.DrawImageUnscaled(bmp, 0, 0);
        }

        private void gMapControl1_MouseUp(object sender, MouseEventArgs e)
        {
            var posstart = gMapControl1.FromLatLngToLocal(MouseDownStart);
            var MouseDownEnd = gMapControl1.FromLocalToLatLng(e.X, e.Y);
            Console.WriteLine("gMapControl1_MouseUp "+ MouseDownEnd);

            if (gMapControl1.Core.IsDragging)
                return;

            if (CurrentGMapMarker != null && CurrentGMapMarker.Tag is MAVState && MouseDownStart == MouseDownEnd && Settings.Instance.GetBoolean("ClickSwapMAV", false))
            {
                var mavstate = CurrentGMapMarker.Tag as MAVState;
                if (mavstate != null)
                {
                    MainV2.comPort = mavstate.parent;
                    MainV2.comPort.sysidcurrent = mavstate.sysid;
                    MainV2.comPort.compidcurrent = mavstate.compid;
                }
            }

            if (Math.Abs(posstart.X - e.X) <=2 && Math.Abs(posstart.Y - e.Y) <=2 && e.Button == MouseButtons.Left)
            {
               // contextMenuStripMap.Show(gMapControl1, e.Location);
            }
        }

        private void setBatteryCellCountToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (hud1.displayCellVoltage)
            {
                hud1.displayCellVoltage = false;
                Settings.Instance["HUD_showbatterycell"] = false.ToString();
                return;
            }

            string CellCount = "4";
            int iCellCount;

            if (DialogResult.Cancel == InputBox.Show("Battery Cell Count", "Cell Count", ref CellCount))
                return;

            if (!int.TryParse(CellCount, out iCellCount))
            {
                CustomMessageBox.Show("Bad Radius");
                return;
            }
            Settings.Instance["HUD_batterycellcount"] = iCellCount.ToString();
            Settings.Instance["HUD_showbatterycell"] = true.ToString();

            hud1.displayCellVoltage = true;
            hud1.batterycellcount = iCellCount;
        }
        private bool tabQuickDetached = false;
        private bool tuningwasrightclick;

        private void undockDockToolStripMenuItem_Click(object sender, EventArgs e)
        {

            Form dropout = new Form();
            TabControl tab = new TabControl();
            dropout.FormBorderStyle = FormBorderStyle.Sizable;
            dropout.ShowInTaskbar = false;
            dropout.Size = new Size(300, 450);
            tabQuickDetached = true;
            tab.Appearance = TabAppearance.FlatButtons;
            tab.ItemSize = new Size(0, 0);
            tab.SizeMode = TabSizeMode.Fixed;
            tab.Size = new Size(dropout.ClientSize.Width, dropout.ClientSize.Height + 22);
            tab.Location = new Point(0, -22);

            tab.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;

            dropout.Text = "Flight DATA";
            tabControlactions.Controls.Remove(tabQuick);
            tab.Controls.Add(tabQuick);
            tabQuick.BorderStyle = BorderStyle.Fixed3D;
            dropout.FormClosed += dropoutQuick_FormClosed;
            dropout.Controls.Add(tab);
            dropout.RestoreStartupLocation();
            dropout.Show();
            tabQuickDetached = true;
            (sender as ToolStripMenuItem).Visible = false;
        }

        void dropoutQuick_FormClosed(object sender, FormClosedEventArgs e)
        {
            (sender as Form).SaveStartupLocation();
            tabControlactions.Controls.Add(tabQuick);
            tabControlactions.SelectedTab = tabQuick;
            tabQuickDetached = false;
            contextMenuStripQuickView.Items["undockToolStripMenuItem"].Visible = true;
        }

        private void IDENT_btn_Click(object sender, EventArgs e)
        {

            MainV2.comPort.uAvionixADSBControl(int.MaxValue,
                                               (ushort)Squawk_nud.Value,
                                               /*UAVIONIX_ADSB_OUT_CONTROL_STATE*/(byte)(
                                                   8 |
                                                   (Mode_clb.GetItemChecked(0) ? 16 : 0) |
                                                   (Mode_clb.GetItemChecked(1) ? 32 : 0) |
                                                   (Mode_clb.GetItemChecked(2) ? 64 : 0) |
                                                   (Mode_clb.GetItemChecked(3) ? 128 : 0)
                                                ),
                                               0,/*UAVIONIX_ADSB_EMERGENCY_STATUS*/
                                               Encoding.ASCII.GetBytes(FlightID_tb.Text),
                                               0);
        }

        private void FlightID_tb_TextChanged(object sender, EventArgs e)
        {
            if (FlightID_tb.Text.Length > 8)
            {
                FlightID_tb.TextChanged -= new EventHandler(FlightID_tb_TextChanged);
                FlightID_tb.Text = FlightID_tb.Text.Substring(0, 8);
                FlightID_tb.TextChanged += new EventHandler(FlightID_tb_TextChanged);
            }
            MainV2.comPort.uAvionixADSBControl(int.MaxValue,
                                               (ushort)Squawk_nud.Value,
                                               /*UAVIONIX_ADSB_OUT_CONTROL_STATE*/(byte)(
                                                   (Mode_clb.GetItemChecked(0) ? 16 : 0) |
                                                   (Mode_clb.GetItemChecked(1) ? 32 : 0) |
                                                   (Mode_clb.GetItemChecked(2) ? 64 : 0) |
                                                   (Mode_clb.GetItemChecked(3) ? 128 : 0)
                                               ),
                                               0,/*UAVIONIX_ADSB_EMERGENCY_STATUS*/
                                               Encoding.ASCII.GetBytes(FlightID_tb.Text),
                                               0);
        }

        private void Squawk_nud_ValueChanged(object sender, EventArgs e)
        {
            UInt16 ones = (UInt16)(Squawk_nud.Value % 10);
            UInt16 tens = (UInt16)((Squawk_nud.Value / 10) % 10);
            UInt16 hundreds = (UInt16)((Squawk_nud.Value / 100) % 10);
            UInt16 thousands = (UInt16)((Squawk_nud.Value / 1000) % 10);

            if (ones == 9)
                ones = 7;
            if (tens == 9)
                tens = 7;
            if (hundreds == 9)
                hundreds = 7;
            if (thousands == 9)
                thousands = 7;

            if (ones > 7)
            {
                tens++;
                ones = 0;
            }
            if (tens > 7)
            {
                hundreds++;
                tens = 0;
            }
            if (hundreds > 7)
            {
                hundreds = 0;
                thousands++;
            }
            if (thousands > 7)
            {
                thousands = 7;
            }

            Squawk_nud.ValueChanged -= new EventHandler(Squawk_nud_ValueChanged);
            Squawk_nud.Value = ((thousands * 1000) + (hundreds * 100) + (tens * 10) + ones);
            Squawk_nud.ValueChanged += new EventHandler(Squawk_nud_ValueChanged);

            MainV2.comPort.uAvionixADSBControl(int.MaxValue,
                                               (ushort)Squawk_nud.Value,
                                               /*UAVIONIX_ADSB_OUT_CONTROL_STATE*/(byte)(
                                                   (Mode_clb.GetItemChecked(0) ? 16 : 0) |
                                                   (Mode_clb.GetItemChecked(1) ? 32 : 0) |
                                                   (Mode_clb.GetItemChecked(2) ? 64 : 0) |
                                                   (Mode_clb.GetItemChecked(3) ? 128 : 0)
                                               ),
                                               0,/*UAVIONIX_ADSB_EMERGENCY_STATUS*/
                                               Encoding.ASCII.GetBytes(FlightID_tb.Text),
                                               0);
        }

        private void STBY_btn_Click(object sender, EventArgs e)
        {
            Mode_clb.SetItemChecked(0, false);
            Mode_clb.SetItemChecked(1, false);
            Mode_clb.SetItemChecked(2, false);
            Mode_clb.SetItemChecked(3, false);
            MainV2.comPort.uAvionixADSBControl(int.MaxValue,
                                               (ushort)Squawk_nud.Value,
                                               /*UAVIONIX_ADSB_OUT_CONTROL_STATE*/(byte)(
                                                   (Mode_clb.GetItemChecked(0) ? 16 : 0) |
                                                   (Mode_clb.GetItemChecked(1) ? 32 : 0) |
                                                   (Mode_clb.GetItemChecked(2) ? 64 : 0) |
                                                   (Mode_clb.GetItemChecked(3) ? 128 : 0)
                                               ),
                                               0,/*UAVIONIX_ADSB_EMERGENCY_STATUS*/
                                               Encoding.ASCII.GetBytes(FlightID_tb.Text),
                                               0);
            STBY_btn.Font = new Font(STBY_btn.Font, FontStyle.Bold);
            ON_btn.Font = new Font(ON_btn.Font, FontStyle.Regular);
            ALT_btn.Font = new Font(ALT_btn.Font, FontStyle.Regular);
        }

        private void ON_btn_Click(object sender, EventArgs e)
        {
            Mode_clb.SetItemChecked(0, true);
            Mode_clb.SetItemChecked(1, false);
            Mode_clb.SetItemChecked(2, true);
            Mode_clb.SetItemChecked(3, true);
            MainV2.comPort.uAvionixADSBControl(int.MaxValue,
                                               (ushort)Squawk_nud.Value,
                                               /*UAVIONIX_ADSB_OUT_CONTROL_STATE*/(byte)(
                                                   (Mode_clb.GetItemChecked(0) ? 16 : 0) |
                                                   (Mode_clb.GetItemChecked(1) ? 32 : 0) |
                                                   (Mode_clb.GetItemChecked(2) ? 64 : 0) |
                                                   (Mode_clb.GetItemChecked(3) ? 128 : 0)
                                               ),
                                               0,/*UAVIONIX_ADSB_EMERGENCY_STATUS*/
                                               Encoding.ASCII.GetBytes(FlightID_tb.Text),
                                               0);
            STBY_btn.Font = new Font(STBY_btn.Font, FontStyle.Regular);
            ON_btn.Font = new Font(ON_btn.Font, FontStyle.Bold);
            ALT_btn.Font = new Font(ALT_btn.Font, FontStyle.Regular);
        }

        private void ALT_btn_Click(object sender, EventArgs e)
        {
            Mode_clb.SetItemChecked(0, true);
            Mode_clb.SetItemChecked(1, true);
            Mode_clb.SetItemChecked(2, true);
            Mode_clb.SetItemChecked(3, true);
            MainV2.comPort.uAvionixADSBControl(int.MaxValue,
                                               (ushort)Squawk_nud.Value,
                                               /*UAVIONIX_ADSB_OUT_CONTROL_STATE*/(byte)(
                                                   (Mode_clb.GetItemChecked(0) ? 16 : 0) |
                                                   (Mode_clb.GetItemChecked(1) ? 32 : 0) |
                                                   (Mode_clb.GetItemChecked(2) ? 64 : 0) |
                                                   (Mode_clb.GetItemChecked(3) ? 128 : 0)
                                               ),
                                               0,/*UAVIONIX_ADSB_EMERGENCY_STATUS*/
                                               Encoding.ASCII.GetBytes(FlightID_tb.Text),
                                               0);
            STBY_btn.Font = new Font(STBY_btn.Font, FontStyle.Regular);
            ON_btn.Font = new Font(ON_btn.Font, FontStyle.Regular);
            ALT_btn.Font = new Font(ALT_btn.Font, FontStyle.Bold);
        }


        private void Squawk_nud_MouseWheel(object sender, MouseEventArgs e)
        {
            NumericUpDown control = (NumericUpDown)sender;
            ((HandledMouseEventArgs)e).Handled = true;
            decimal value = control.Value + ((e.Delta > 0) ? control.Increment : -control.Increment);
            control.Value = Math.Max(control.Minimum, Math.Min(value, control.Maximum));
        }

        private void XPDRConnect_btn_Click(object sender, EventArgs e)
        {
            try
            {
                MainV2.comPort.doCommand(MAVLink.MAV_CMD.SET_MESSAGE_INTERVAL, (float) MAVLink.MAVLINK_MSG_ID.UAVIONIX_ADSB_OUT_STATUS, (float) 1000000.0, 0, 0, 0, 0, 0);
                var start = DateTime.Now;
                while (!MainV2.comPort.MAV.cs.xpdr_status_pending && (DateTime.Now - start).TotalSeconds < 3); // wait until we receive a status message
                if (MainV2.comPort.MAV.cs.xpdr_status_pending)
                {
                    updateTransponder();
                }
                else CustomMessageBox.Show("Timeout: Status message not received.");

            }
            catch (Exception ex)
            {
                CustomMessageBox.Show("Timeout.");
            }
        }

        private void updateTransponder()
        {
            if (MainV2.comPort.BaseStream == null || !MainV2.comPort.BaseStream.IsOpen)
                return;

            if (!MainV2.comPort.MAV.cs.xpdr_status_pending)
            {
                // timeout on status message
                STBY_btn.Enabled = false;
                ON_btn.Enabled = false;
                ALT_btn.Enabled = false;
                IDENT_btn.Enabled = false;
                FlightID_tb.Enabled = false;
                Squawk_nud.Enabled = false;

                if (transponderNeverConnected)
                {
                    XPDRConnect_btn.Text = "Connect To Transponder";
                    XPDRConnect_btn.Enabled = true;
                }
                else
                {
                    // if we have connected before, we should have subscribed to the status message.
                    // something must have reset the message interval (AP power cycled, etc.)
                    // so indicate that the connection reset
                    XPDRConnect_btn.Text = "Transponder Status Lost";
                    XPDRConnect_btn.Enabled = true;
                    transponderNeverConnected = true;
                }
            }
            else if (!MainV2.comPort.MAV.cs.xpdr_status_unavail)
            {
                if (transponderNeverConnected)
                {
                    // subscribe to status message on first connection
                    MainV2.comPort.doCommand(MAVLink.MAV_CMD.SET_MESSAGE_INTERVAL, (float)MAVLink.MAVLINK_MSG_ID.UAVIONIX_ADSB_OUT_STATUS, (float)1000000.0, 0, 0, 0, 0, 0);
                        transponderNeverConnected = false;
                }

                STBY_btn.Enabled = true;
                ON_btn.Enabled = true;
                ALT_btn.Enabled = true;
                IDENT_btn.Enabled = true;
                FlightID_tb.Enabled = true;
                Squawk_nud.Enabled = true;

                if (!(STBY_btn.Focused || ON_btn.Focused || ALT_btn.Focused))
                {
                    Mode_clb.SetItemChecked(0, MainV2.comPort.MAV.cs.xpdr_mode_A_enabled);
                    Mode_clb.SetItemChecked(1, MainV2.comPort.MAV.cs.xpdr_mode_C_enabled);
                    Mode_clb.SetItemChecked(2, MainV2.comPort.MAV.cs.xpdr_mode_S_enabled);
                    Mode_clb.SetItemChecked(3, MainV2.comPort.MAV.cs.xpdr_es1090_tx_enabled);
                    STBY_btn.Font = new Font(STBY_btn.Font, (!Mode_clb.GetItemChecked(0) &&
                                                             !Mode_clb.GetItemChecked(1) &&
                                                             !Mode_clb.GetItemChecked(2) &&
                                                             !Mode_clb.GetItemChecked(3)) ? FontStyle.Bold : FontStyle.Regular);
                    ON_btn.Font   = new Font(ON_btn.Font,   ( Mode_clb.GetItemChecked(0) &&
                                                             !Mode_clb.GetItemChecked(1) &&
                                                              Mode_clb.GetItemChecked(2) &&
                                                              Mode_clb.GetItemChecked(3)) ? FontStyle.Bold : FontStyle.Regular);
                    ALT_btn.Font  = new Font(ALT_btn.Font,  ( Mode_clb.GetItemChecked(0) &&
                                                              Mode_clb.GetItemChecked(1) &&
                                                              Mode_clb.GetItemChecked(2) &&
                                                              Mode_clb.GetItemChecked(3)) ? FontStyle.Bold : FontStyle.Regular);
                }

                fault_clb.SetItemChecked(0, MainV2.comPort.MAV.cs.xpdr_maint_req);
                fault_clb.SetItemChecked(1, MainV2.comPort.MAV.cs.xpdr_gps_unavail);
                fault_clb.SetItemChecked(2, MainV2.comPort.MAV.cs.xpdr_gps_no_fix);
                fault_clb.SetItemChecked(3, MainV2.comPort.MAV.cs.xpdr_adsb_tx_sys_fail);
                fault_clb.SetItemChecked(4, MainV2.comPort.MAV.cs.xpdr_airborne_status);

                if (!FlightID_tb.Focused)
                {
                    FlightID_tb.TextChanged -= new EventHandler(FlightID_tb_TextChanged);
                    FlightID_tb.Text = System.Text.Encoding.UTF8.GetString(MainV2.comPort.MAV.cs.xpdr_flight_id);
                    FlightID_tb.TextChanged += new EventHandler(FlightID_tb_TextChanged);
                }

                if (!Squawk_nud.Focused)
                {
                    Squawk_nud.ValueChanged -= new EventHandler(Squawk_nud_ValueChanged);
                    try
                    {
                        Squawk_nud.Value = (decimal)MainV2.comPort.MAV.cs.xpdr_mode_A_squawk_code;
                        // if the value is bad, we need to be able to reset it, so silent fail
                    }
                    catch
                    {
                    }
                    Squawk_nud.ValueChanged += new EventHandler(Squawk_nud_ValueChanged);
                }

                NIC_tb.Text = NIC_table[MainV2.comPort.MAV.cs.xpdr_nic];
                NACp_tb.Text = NACp_table[MainV2.comPort.MAV.cs.xpdr_nacp];

                IDENT_btn.Font = new Font(IDENT_btn.Font, MainV2.comPort.MAV.cs.xpdr_ident_active ? FontStyle.Bold : FontStyle.Regular);

                XPDRConnect_btn.Text = "Transponder Connected!";
                XPDRConnect_btn.Enabled = false;
            }
            else
            {
                STBY_btn.Enabled = false;
                ON_btn.Enabled = false;
                ALT_btn.Enabled = false;
                IDENT_btn.Enabled = false;
                FlightID_tb.Enabled = false;
                Squawk_nud.Enabled = false;

                XPDRConnect_btn.Text = "Transponder Offline";
                XPDRConnect_btn.Enabled = false;
            }
            MainV2.comPort.MAV.cs.xpdr_status_pending = false;
        }

        private void showIconsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            myhud.displayicons = !myhud.displayicons;
            Settings.Instance["HUD_showicons"] = myhud.displayicons.ToString();
            if (myhud.displayicons)
            {
                showIconsToolStripMenuItem.Text = "Show text";
            }
            else
            {
                showIconsToolStripMenuItem.Text = "Show icons";
            }
        }

        private void multiLineToolStripMenuItem_Click(object sender, EventArgs e)
        {
            tabControlactions.Multiline = !tabControlactions.Multiline;
            Settings.Instance["tabControlactions_Multiline"] = tabControlactions.Multiline.ToString();
        }

        private void jumpToTagToolStripMenuItem_Click(object sender, EventArgs e)
        {
            string tag_str = "";
            if (InputBox.Show("Jump to Tag", "Tag Id:", ref tag_str) != DialogResult.OK)
            {
                return;
            }

            UInt16 tag;
            if (!UInt16.TryParse(tag_str, out tag) || tag < 0 || tag > 0xFFFF)
            {
                CustomMessageBox.Show("Invalid Tag. Must be a number from 0 to 65535");
                // NOTE: This is recursive to automatically re-pop up the dialog box
                // on input error for as many times as you try to enter an invalid number.
                jumpToTagToolStripMenuItem_Click(null, null);
                return;
            }

            try {
                if (!MainV2.comPort.doCommand(MAVLink.MAV_CMD.DO_JUMP_TAG, tag, 0, 0, 0, 0, 0, 0))
                {
                    CustomMessageBox.Show(Strings.CommandFailed, Strings.ERROR);
                }
            }
            catch (Exception ex)
            {
                CustomMessageBox.Show(Strings.CommandFailed + ex.ToString(), Strings.ERROR);
            }
        }

        ToolStripMenuItem gimbalVideoShowMiniMap = new ToolStripMenuItem("Mini map");
        ToolStripMenuItem gimbalVideoSwapPosition = new ToolStripMenuItem("Swap with map");
        ToolStripMenuItem gimbalVideoClose = new ToolStripMenuItem("Close");
        bool gimbalMenuHandlersInitialized = false;
        GimbalVideoControl _gimbalVideoControl;
        GimbalVideoControl gimbalVideoControl
        {
            get
            {
                // If this is the first call, create the handlers for the context menu items
                if (!gimbalMenuHandlersInitialized)
                {
                    gimbalMenuHandlersInitialized = true;
                    gimbalVideoShowMiniMap.CheckedChanged += (s, ev) =>
                    {
                        gMapControl1.Visible = gimbalVideoShowMiniMap.Checked;
                        gimbalVideoSwapPosition.Visible = gimbalVideoShowMiniMap.Checked;
                    };
                    gimbalVideoSwapPosition.Click += (s, ev) =>
                    {
                        if (gimbalVideoControl.Dock == DockStyle.None)
                        {
                            gimbalVideoFullSizedToolStripMenuItem_Click(null, null);
                        }
                        else
                        {
                            gimbalVideoMiniToolStripMenuItem_Click(null, null);
                        }
                    };
                    gimbalVideoClose.Click += (s, ev) =>
                    {
                        gimbalVideoMiniToolStripMenuItem_Click(null, null);
                        gimbalVideoControl.Visible = false;
                        gimbalVideoControl.Stop();
                        gimbalVideoControl.Dispose();
                    };
                }
                // Check if we need to construct a gimbalVideoControl
                if (_gimbalVideoControl == null || _gimbalVideoControl.IsDisposed)
                {
                    _gimbalVideoControl = new GimbalVideoControl();
                    _gimbalVideoControl.Dock = DockStyle.Fill;

                    // Add option to show/hide minimap
                    gimbalVideoShowMiniMap.CheckOnClick = true;
                    gimbalVideoShowMiniMap.Checked = true;

                    _gimbalVideoControl.VideoBoxContextMenu.Items.Add(gimbalVideoShowMiniMap);
                    _gimbalVideoControl.VideoBoxContextMenu.Items.Add(gimbalVideoSwapPosition);
                    _gimbalVideoControl.VideoBoxContextMenu.Items.Add(gimbalVideoClose);
                }

                return _gimbalVideoControl;
            }
        }

        // Resize the mini video or mini map when the container is resized
        private void splitContainer1_Panel2_Resize(object sender, EventArgs e)
        {
            bool miniVideo = splitContainer1.Panel2.Contains(_gimbalVideoControl)
                && _gimbalVideoControl?.Dock == DockStyle.None
                && _gimbalVideoControl.Visible;
            bool miniMap = gMapControl1.Dock == DockStyle.None && gMapControl1.Visible;
            if (miniVideo)
            {
                var width = (int)(splitContainer1.Panel2.Width * 0.3);
                var height = (int)(splitContainer1.Panel2.Height * 0.3);
                var aspectRatio = _gimbalVideoControl.VideoBox.Image.Width / (double)_gimbalVideoControl.VideoBox.Image.Height;
                (width, height) = (
                    Math.Min(width, (int)(height * aspectRatio)),
                    Math.Min(height, (int)(width / aspectRatio))
                );
                var x = splitContainer1.Panel2.Width - width - TRK_zoom.Width;
                var y = splitContainer1.Panel2.Height - height;
                _gimbalVideoControl.Location = new Point(x, y);
                _gimbalVideoControl.Size = new Size(width, height);
            }
            else if (miniMap)
            {
                var width = (int)(splitContainer1.Panel2.Width * 0.3);
                var height = (int)(splitContainer1.Panel2.Height * 0.3);
                var x = splitContainer1.Panel2.Width - width;
                var y = splitContainer1.Panel2.Height - height;
                gMapControl1.Location = new Point(x, y);
                gMapControl1.Size = new Size(width, height);
            }

            Invalidate();
        }

        private void gimbalVideoFullSizedToolStripMenuItem_Click(object sender, EventArgs e)
        {
            // If the gimbal video is in its own window, close it
            var containingForm = gimbalVideoControl.Parent as Form;

            // Fill the panel with the gimbal video control
            splitContainer1.Panel2.Controls.Add(gimbalVideoControl);
            gimbalVideoControl.Dock = DockStyle.Fill;
            gimbalVideoControl.BringToFront(); // Place on top of all map overlay controls
            gimbalVideoControl.Visible = true;

            // Add the map panel to the mini map panel
            gMapControl1.Dock = DockStyle.None;
            gMapControl1.BringToFront();
            gMapControl1.Visible = gimbalVideoShowMiniMap.Checked;

            // Call resize to correctly position the mini map
            splitContainer1_Panel2_Resize(null, null);

            // Reconfigure context menu controls
            gimbalVideoShowMiniMap.Visible = true;
            gimbalVideoSwapPosition.Visible = gimbalVideoShowMiniMap.Checked;
            gimbalVideoClose.Visible = true;

            containingForm?.Close();
        }

        private void gimbalVideoMiniToolStripMenuItem_Click(object sender, EventArgs e)
        {
            // If the gimbal video is in its own window, close it
            var containingForm = gimbalVideoControl.Parent as Form;

            // Fill the panel with the map
            gMapControl1.Dock = DockStyle.Fill;
            gMapControl1.Visible = true;
            gMapControl1.SendToBack(); // Behind the map overlay controls

            // Add the gimbal video control to the mini video panel
            splitContainer1.Panel2.Controls.Add(gimbalVideoControl);
            gimbalVideoControl.Dock = DockStyle.None;
            gimbalVideoControl.BringToFront();
            gimbalVideoControl.Visible = true;

            // Call resize to correctly position the mini video
            splitContainer1_Panel2_Resize(null, null);

            // Reconfigure context menu controls
            gimbalVideoShowMiniMap.Visible = false;
            gimbalVideoSwapPosition.Visible = true;
            gimbalVideoClose.Visible = true;

            containingForm?.Close();
        }

        private void gimbalVideoPopOutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            // See if the gimbal video is already in its own window
            if (gimbalVideoControl.Parent is Form)
            {
                // Remove from the form and dispose the form
                // (in case the form has ended up off screen or something)
                var ParentForm = gimbalVideoControl.Parent as Form;
                ParentForm.Controls.Remove(gimbalVideoControl);
                ParentForm.Close();
            }

            // Restore the map to full sized if necessary
            gMapControl1.Dock = DockStyle.Fill;
            gMapControl1.SendToBack();
            gMapControl1.Visible = true;

            var form = new Form()
            {
                Text = "Gimbal Control",
                Size = new Size(600, 400),
                StartPosition = FormStartPosition.CenterParent
            };
            form.Controls.Add(gimbalVideoControl);
            gimbalVideoControl.Dock = DockStyle.Fill;
            gimbalVideoControl.Visible = true;

            // Reconfigure context menu controls
            gimbalVideoShowMiniMap.Visible = false;
            gimbalVideoSwapPosition.Visible = false;
            gimbalVideoClose.Visible = false;

            // Pass `this` to keep the pop-out always on top
            form.Show(this);
        }
    }
}
